package cn.qingyun.gis.modules.scenes.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.qingyun.gis.common.Result;
import cn.qingyun.gis.exception.CommonException;
import cn.qingyun.gis.kafka.service.KafkaProducerService;
import cn.qingyun.gis.minio.util.MinioTool;
import cn.qingyun.gis.modules.alongstreet.service.IAlongStreetProofreadService;
import cn.qingyun.gis.modules.express.constant.ExpressStatus;
import cn.qingyun.gis.modules.express.constant.RedisContant;
import cn.qingyun.gis.modules.express.entity.ExpressRegion;
import cn.qingyun.gis.modules.express.request.HwGetGridIdRequest;
import cn.qingyun.gis.modules.express.response.HwGridByNumResponse;
import cn.qingyun.gis.modules.express.response.RoleInfoResponse;
import cn.qingyun.gis.modules.express.service.IExpressRegionService;
import cn.qingyun.gis.modules.express.service.IHwRestApiService;
import cn.qingyun.gis.modules.express.util.SyncTool;
import cn.qingyun.gis.modules.handle.LongestMatchColumnHandler;
import cn.qingyun.gis.modules.init.system.constant.enums.RegionNumPermissionEnum;
import cn.qingyun.gis.modules.init.system.constant.enums.RoleCodeEnum;
import cn.qingyun.gis.modules.init.system.vo.LoginUser;
import cn.qingyun.gis.modules.init.utils.FutureTool;
import cn.qingyun.gis.modules.init.utils.SystemUtil;
import cn.qingyun.gis.modules.middle.api.standard.request.sub.QKAddressAttr;
import cn.qingyun.gis.modules.middle.api.standard.response.RgeoAddressVo;
import cn.qingyun.gis.modules.scenes.contant.ComConstant;
import cn.qingyun.gis.modules.scenes.contant.ScenesStatus;
import cn.qingyun.gis.modules.scenes.contant.TypeStatus;
import cn.qingyun.gis.modules.scenes.conver.BusinessStateConverter;
import cn.qingyun.gis.modules.scenes.conver.CustomEnumConverter;
import cn.qingyun.gis.modules.scenes.conver.DatetimeConverter;
import cn.qingyun.gis.modules.scenes.conver.OperatorConverter;
import cn.qingyun.gis.modules.scenes.entity.*;
import cn.qingyun.gis.modules.scenes.feign.PoiDetailClientService;
import cn.qingyun.gis.modules.scenes.mapper.RegionAddrMapper;
import cn.qingyun.gis.modules.scenes.request.*;
import cn.qingyun.gis.modules.scenes.response.*;
import cn.qingyun.gis.modules.scenes.service.*;
import cn.qingyun.gis.modules.scenes.util.GdRgeoTool;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.metadata.property.ExcelContentProperty;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.fastjson.JSON;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.xml.bind.DatatypeConverter;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.stream.Collectors;

import static cn.qingyun.gis.modules.init.utils.GeometryTool.isValid;
import static cn.qingyun.gis.modules.scenes.contant.ScenesStatus.fromDescription;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author guest
 * @since 2024-04-28
 */
@Slf4j
@Service
@DS("scenes_offensive")
public class PoiProofreadServiceImpl implements IPoiProofreadService {
    @Resource
    private IPoiScenarioService iPoiScenarioService;
    @Resource
    private IPoiScenarioAppendixService iPoiScenarioAppendixService;

    @Resource
    private IPoiScenarioProofreadService iPoiScenarioProofreadService;

    @Resource
    private IExpressRegionService iExpressRegionService;

    @Resource
    private RedissonClient redissonClient;

    @Resource
    private IAlongStreetProofreadService iAlongStreetProofreadService;

    @Resource
    private HttpServletResponse response;

    @Resource
    private IHwRestApiService hwRestApiService;

    @Resource
    private RegionAddrMapper regionAddrMapper;

    @Resource
    private IPoiScenarioChannelService iPoiScenarioChannelService;

    @Resource
    private IPoiNumberInfoService iPoiNumberInfoService;
    @Resource
    private PoiUserPermissionService poiUserPermissionService;
    @Resource
    private IPoiGovernmentService iPoiGovernmentService;
    @Resource
    private PoiScenarioProofreadDraftService draftService;
    @Resource
    private PoiWgtInvokeService poiWgtInvokeService;

    @Value("${qingyun.sso.valid.enabled:false}")
    private Boolean ssoValid;

    @Value("${qingyun.speech.convert-word-url}")
    private String convertWordUrl;

    @Value("${qingyun.speech.enabled}")
    private Boolean enabled;

    @Value("${qingyun.project.service-host:http://localhost:8080}")
    private String projectPath;

    @Value("${qingyun.exportPhoto.service-host:http://127.0.0.1:3000/#/}")
    private String exportHost;

    @Value("${qingyun.jingfen.service-host:http://127.0.0.1:3000/#/}")
    private String jfUrl;

    @Value("${qingyun.jingfen.enabled}")
    private Boolean jfEnabled;
    @Value("${qingyun.optical-modem.scan-url}")
    private String opticalModemUrl;

    @Value("${qingyun.optical-modem.enabled}")
    private Boolean opticalModemEnabled;
    private static final String BASE64_HEADER = "data:image/jpeg;base64,";
    @Resource
    private PoiDetailClientService poiDetailClientService;

    @Resource
    private KafkaProducerService kafkaProducerService;
    @Resource
    private UniAddrRegionService uniAddrRegionService;
    @Value("${spring.profiles.active}")
    private String env;

    @Override
    public IPage<PoiListResponse> poiQueryNew(PoiListRequest request) {
        log.info("列表查询传入参数：{}", request);
        // 判断经纬度是否有效
        if (!isValid(String.format("POINT(%s %s)", request.getLon(), request.getLat()))) {
            log.error("当前传入经纬度无效");
            throw new CommonException("当前传入经纬度无效");
        }

        IPage<PoiScenario> poiStreetIPage = new Page<>(request.getPageNum(), request.getPageSize());
        return iPoiScenarioChannelService.selectPagePoiCommon(poiStreetIPage, request, "poi_scenario");
    }

    // 合并商业综合体数据到商务楼宇类型中
    private static void mergeTypes(Map<String, Map<Integer, Integer>> map, String type1, String type2) {
        Map<Integer, Integer> businessBuildingData = map.get(type1);
        Map<Integer, Integer> commercialComplexData = map.get(type2);
        if (commercialComplexData != null) {
            if (businessBuildingData == null) {
                businessBuildingData = new HashMap<>();
                map.put(type1, businessBuildingData);
            }
            Map<Integer, Integer> finalBusinessBuildingData = businessBuildingData;
            commercialComplexData.forEach((isCorrected, count) -> finalBusinessBuildingData.merge(isCorrected, count, Integer::sum));
            // 移除商业综合体类型的数据
            map.remove(type2);
        }
    }

    //解析门牌号字符串
    public static String parseRoadNoStr(String roadNoStr) {
        String result = null;
        if (StringUtils.isEmpty(roadNoStr)) {
            return roadNoStr;
        }
        String subStr = roadNoStr.replaceAll("[^0-9-]", "");
        String[] array = subStr.split("\\D+");
        if (array.length > 0) {
            if (array.length == 1) {
                result = array[0];
            }
            if (array.length >= 2) {
                result = array[0] + "-" + array[array.length - 1];
            }
        }
        log.debug("解析高德返回的门牌号路巷街值入参{}，结果{}", roadNoStr, result);
        return result;
    }

    @Override
    public IPage<PoiListResponse> poiQueryList(PoiListRequest request) {
        Integer level = uniAddrRegionService.selectLevel(request.getCodeStr());
        IPage<PoiScenario> poiStreetIPage = new Page<>(request.getPageNum(), request.getPageSize());
        IPage<PoiListResponse> responseIPage = iPoiScenarioChannelService.selectPagePoiCommonNew(poiStreetIPage, request, "poi_scenario", level);
        if (!fromDescription(request.getType()).equals(ScenesStatus.STREET)) {
            List<PoiListResponse> poiListResponses = handlerList(request.getType(), responseIPage.getRecords());
            responseIPage.setRecords(poiListResponses);
        }

        return responseIPage;
    }

    @Override
    public TaskDetailResponse followQueryById(String id, String type) {
        return iPoiScenarioService.queryTaskDetailById(id);
    }

    //补充宽带渗透率、摸排情况（楼宇、产业园区、专业市场）
    private List<PoiListResponse> handlerList(String type, List<PoiListResponse> records) {
        if (type.contains(ScenesStatus.BUILD.getDesc()) || type.equals(ScenesStatus.MARKET.getDesc()) ||
                type.equals(ScenesStatus.PARK.getDesc())) {
            List<String> collect = records.stream().map(PoiListResponse::getPoiId).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(collect)) {
                List<PoiSceneCount> poiSceneCounts = iPoiScenarioService.selectBuildCount(collect);
                //已随访，未随访
                for (PoiListResponse record : records) {
                    //替换原数据的商业综合体--->商务楼宇
                    if (ScenesStatus.COMPLEX.getDesc().equals(record.getType())) {
                        record.setType(ScenesStatus.BUSINESS.getDesc());
                    }
                    String poiId = record.getPoiId();
                    int belongOperatorZeroTotal = 0;
                    int belongOperatorTotal = 0;
                    for (PoiSceneCount poiSceneCount : poiSceneCounts) {
                        if (poiId.equals(poiSceneCount.getPoiId())) {
                            //随访个数补充
                            if (poiSceneCount.getKwState() == 1) {
                                record.setKwPoiTotal(record.getKwPoiTotal() + poiSceneCount.getPoiCount());
                            }
                            if (poiSceneCount.getKwState() == 0) {
                                record.setUnKwPoiTotal(record.getUnKwPoiTotal() + poiSceneCount.getPoiCount());
                            }
                            if (poiSceneCount.getKwState() != null && poiSceneCount.getKwState() == 1) {
                                if (poiSceneCount.getBusinessState() == null || poiSceneCount.getBusinessState() != 2) {
                                    //我网宽带个数
                                    if (poiSceneCount.getBelongOperator() != null && poiSceneCount.getBelongOperator().equals(0)) {
                                        belongOperatorZeroTotal += poiSceneCount.getPoiCount();
                                    }
                                    belongOperatorTotal += poiSceneCount.getPoiCount();
                                }
                            }
                        }
                    }
                    if (belongOperatorTotal != 0) {
                        double result = (double) belongOperatorZeroTotal / belongOperatorTotal;
                        String formattedResult = String.format("%.2f", result);
                        double finalResult = Double.parseDouble(formattedResult);
                        record.setKdRate(finalResult);
                    }
                }
                return records;
            }
        }
        return records;
    }

    @Override
    public UnFollowPoiDto noFollowQueryById(String id, String type) {
        UnFollowPoiDto res = new UnFollowPoiDto();
        PoiScenario poiScenario = iPoiScenarioService.getById(id);
        if (ObjectUtil.isNull(poiScenario)) {
            throw new CommonException(String.format("摸牌数据查询失败[%s]", id));
        }
        BeanUtil.copyProperties(poiScenario, res);
        //赋值 网络是否覆盖字段
        Integer zoneCodeFlag = iPoiGovernmentService.selectZoneTypeByPoiId(res.getPoiId());
        res.setIsZoneCode(zoneCodeFlag);
        log.debug("id:{},未随访信息返回，{}", id, res);

        return res;
    }

    @Override
    @Transactional
    public List<String> uploadPhoto(PhotoKwRequest request) {
        List<String> pictureList = request.getPictureList();
        List<String> imageList = Lists.newArrayList();
        if (ObjectUtil.isNotEmpty(request.getPictureList())) {
            for (int i = 0; i < request.getPictureList().size(); i++) {
                // 如果当前传入的是base64字符串
                if (request.getPictureList().get(i).contains("base64")) {
                    String imageName = ("沿街商铺".equals(request.getType()) ? "PHOTO_STREET" : "PHOTO_FIVE") + "_" + IdUtil.simpleUUID() + ".jpg";
                    int index = i;
                    imageList.add(FutureTool.get(FutureTool.getFuture(() -> iAlongStreetProofreadService.uploadBase64Image(imageName, pictureList.get(index)))));
                } else {
                    imageList.add(request.getPictureList().get(i));
                }
            }
        }
        if (imageList.stream().anyMatch(Objects::isNull) || imageList.stream().anyMatch(item -> Objects.equals(item, ""))) {
            throw new CommonException("当前解析图片出错~");
        }
        if (CollUtil.isNotEmpty(imageList)) {
            // 处理 沿街 场景
            List<PoiScenarioAppendix> res = imageList.stream()
                    .map(item -> PoiScenarioAppendix.builder()
                            .poiScenarioId(request.getId())
                            .minioPath(item)
                            .type(TypeStatus.PHOTO.getDesc())
                            .createTime(DateUtil.date())
                            .proofreadId(request.getProofreadId())
                            .build())
                    .collect(Collectors.toList());
            iPoiScenarioAppendixService.saveBatch(res);
        }

        return imageList;

    }

    @Override
    @Transactional
    public String proofread(PoiKwRequest request) {
        log.debug("摸排接口入参，{}", request);
        RLock rlock = redissonClient.getLock(RedisContant.SCENES_PROOF_LOCK + request.getId());
        try {
            boolean lockRes = rlock.tryLock(10, TimeUnit.SECONDS);
            List<String> photos = null;
            if (lockRes) {
                String chainId = request.getChainId();
                // 上传图片
                if (CollUtil.isNotEmpty(request.getPictureList())) {
                    photos = this.uploadPhoto(PhotoKwRequest.builder()
                            .id(request.getId())
                            .type(request.getType())
                            .pictureList(request.getPictureList())
                            .proofreadId(chainId)
                            .build());
                }
                //判断是否生成推送工单
                try {
                    pushOrder(request, photos);
                } catch (Exception e) {
                    log.debug("工单生成报错！{}", e.getMessage());
                }
                //查询是否是第一次随访
                BelongPeopleResponse belongPeopleResponse = iPoiScenarioProofreadService.selectBelongKwPhone(request.getId(), request.getType());

                if (iPoiScenarioService.count(new QueryWrapper<PoiScenario>().lambda().eq(PoiScenario::getId, request.getId())) == 0) {
                    throw new CommonException("当前随访信息不存在");
                }
                //更新lastUpdated为0
                UpdateWrapper<PoiScenarioProofread> updateWrapper = new UpdateWrapper<>();
                updateWrapper.lambda().set(PoiScenarioProofread::getLastUpdated, 0).eq(PoiScenarioProofread::getPoiScenarioId, request.getId());
                boolean update = iPoiScenarioProofreadService.update(updateWrapper);
                // 保存摸牌结果
                PoiScenarioProofread poiScenarioProofread = new PoiScenarioProofread();
                BeanUtil.copyProperties(request, poiScenarioProofread, "id");
                poiScenarioProofread.setPoiScenarioId(request.getId());
                poiScenarioProofread.setKwTime(DateUtil.date());
                poiScenarioProofread.setId(chainId);
                poiScenarioProofread.setLastUpdated(1);
                poiScenarioProofread.setRegionCityCode(request.getRegionCityCode());
                //belongFlag默认值是0
                if (belongPeopleResponse == null) {
                    poiScenarioProofread.setBelongFlag(1);
                }

                // 更新原记录
                PoiScenario poiScenario = new PoiScenario();
                poiScenario.setUpdateTime(DateUtil.date());
                // 标记是否要更新PoiStreet
                boolean success = true;
                if (request.getIsBuild() == 1) {
                    if (!((request.getBusinessState() != null && request.getBusinessState() == 2) || request.getDzBelongOperator() != null)) {
                        poiScenarioProofread.setBelongFlag(0);
                        success = false;
                    }
                }
                if (success) {
                    poiScenario.setKwState(ComConstant.FINISH_KW);
                    iPoiScenarioService.update(poiScenario, new QueryWrapper<PoiScenario>().lambda().eq(PoiScenario::getId, request.getId()));
                }

                boolean saveResult = iPoiScenarioProofreadService.save(poiScenarioProofread);
                if (saveResult){
                    //修改建筑随访状态
                    iPoiScenarioService.updateKwState(request.getId(),request.getType(),request.getRegionCityCode(),request.getIsBuild());
                    //删除暂存过程
                    draftService.deleteTempRecord(request);
                    //摸排结果推送给网格通
                    poiWgtInvokeService.sendKwResultToWgt(request);
                }
                return "勘误成功！";
            }

            return "系统繁忙，请稍后再试";

        } catch (Exception e) {
            log.debug("输入参数，{}，勘误失败,{}", request, e.getMessage());
            throw new CommonException(e.getMessage());
        } finally {
            if (rlock.isHeldByCurrentThread()) {
                rlock.unlock();
            }
        }
    }

    @Override
    public DraftResponse draftProofreadSaveOrUpdate(PoiDraftRequest request) {
        log.debug("草稿记录入参{}",request);
        //1.去查询草稿表中是否有数据，没有则直接保存
        String chainId = request.getChainId();
        QueryWrapper<PoiScenarioProofreadDraft> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(PoiScenarioProofreadDraft::getPoiScenarioId,request.getId()).eq(PoiScenarioProofreadDraft::getKwPhone,request.getKwPhone());
        Integer count = draftService.getBaseMapper().selectCount(wrapper);
        PoiScenarioProofreadDraft poiScenarioProofreadDraft = new PoiScenarioProofreadDraft();
        poiScenarioProofreadDraft.setProofreadId(chainId);
        poiScenarioProofreadDraft.setPoiScenarioId(request.getId());
        BeanUtils.copyProperties(request,poiScenarioProofreadDraft);
        DraftResponse response = new DraftResponse();
        response.setChainId(chainId);
        if (count<=0){
            Date date = new Date();
            poiScenarioProofreadDraft.setId(null);
            poiScenarioProofreadDraft.setCreateTime(date);
            poiScenarioProofreadDraft.setUpdateTime(date);
            poiScenarioProofreadDraft.setContent(JSONUtil.toJsonStr(request));
            draftService.getBaseMapper().insert(poiScenarioProofreadDraft);
        }else {
            //直接更新覆盖
            draftService.updateDraft(request);
        }
        QueryWrapper<PoiScenarioProofreadDraft> wrapperSub = new QueryWrapper<>();
        wrapperSub.lambda().select(PoiScenarioProofreadDraft::getUpdateTime,PoiScenarioProofreadDraft::getProofreadId,PoiScenarioProofreadDraft::getPoiScenarioId)
                .eq(PoiScenarioProofreadDraft::getProofreadId,chainId)
                .eq(PoiScenarioProofreadDraft::getKwPhone,request.getKwPhone());
        PoiScenarioProofreadDraft draft = draftService.getBaseMapper().selectOne(wrapperSub);
        if (draft!=null){
            BeanUtils.copyProperties(draft,response);
        }
        return response;
    }

    @Async
    public void pushOrder(PoiKwRequest request, List<String> photos) {
        log.debug("工单数据推送入参{}", request);
        LambdaQueryWrapper<PoiScenarioProofread> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.select(PoiScenarioProofread::getKwBossTel, PoiScenarioProofread::getBuildInfo, PoiScenarioProofread::getHouseRoad, PoiScenarioProofread::getHouseNumber).eq(PoiScenarioProofread::getPoiScenarioId, request.getId()).orderByDesc(PoiScenarioProofread::getKwTime).last("limit 1");
        PoiScenarioProofread poiScenarioProofreadSub = iPoiScenarioProofreadService.getBaseMapper().selectOne(queryWrapper);
        //调用工单详情接口
        RgeoAddressVo rgeoAddressVo = poiDetailClientService.queryRgeoAddrByGdId(request.getPoiId());
        log.debug("poi详情数据{}", rgeoAddressVo);
        if (rgeoAddressVo == null || (StringUtils.isEmpty(rgeoAddressVo.getProvince()) && StringUtils.isEmpty(rgeoAddressVo.getCity()))) {
            log.debug("推送工单返回结果{}", "未找到POI详情数据！！！");
            return;
        }
        Integer isBuild = request.getIsBuild();
        boolean flag = false;
        if (poiScenarioProofreadSub != null) {
            //已经摸排的话，与上一次摸排数据对比
            rgeoAddressVo.setRoad(poiScenarioProofreadSub.getHouseRoad());
            rgeoAddressVo.setRoadNo(poiScenarioProofreadSub.getHouseNumber());
            //5-6级地址是否修改
            flag = updateRoadInfo(request, rgeoAddressVo);
            //8-11级地址是否修改
            if (request.getBuildInfo() != null && StringUtils.isNotEmpty(request.getBuildInfo().getBuilding()) && isBuild == 0) {
                rgeoAddressVo.setBuild(poiScenarioProofreadSub.getBuildInfo().getBuilding());
                rgeoAddressVo.setCell(poiScenarioProofreadSub.getBuildInfo().getUnit());
                rgeoAddressVo.setFloor(poiScenarioProofreadSub.getBuildInfo().getFloor());
                rgeoAddressVo.setRoom(poiScenarioProofreadSub.getBuildInfo().getRoom());
                flag |= updateBuildingInfo(request.getBuildInfo(), rgeoAddressVo);
            }
        } else {
            //未摸排与原数据比较
            //5-6级地址是否修改
            flag = updateRoadInfo(request, rgeoAddressVo);
            //8-11级地址是否修改
            if (request.getBuildInfo() != null && StringUtils.isNotEmpty(request.getBuildInfo().getBuilding()) && isBuild == 0) {
                flag |= updateBuildingInfo(request.getBuildInfo(), rgeoAddressVo);
            }
        }
        boolean telephoneUpdateFlag = false;
        //对比手机号是否修改
        if (poiScenarioProofreadSub != null) {
            String kwBossTel = poiScenarioProofreadSub.getKwBossTel();
            if (StringUtils.isNotEmpty(request.getKwBossTel()) && !request.getKwBossTel().equals(kwBossTel)) {
                //远程调用接口修改手机号
                if (!flag) {
                    Boolean result = poiDetailClientService.updateTelephone(request.getPoiId(), request.getKwBossTel());
                    log.debug("调用修改手机号结果{}", result);
                }
                telephoneUpdateFlag = true;
            }
        } else {
            //查询对比原数据手机号是否一样
            LambdaQueryWrapper<PoiScenario> wrapper = new LambdaQueryWrapper<>();
            wrapper.select(PoiScenario::getTelephone, PoiScenario::getPoiId).eq(PoiScenario::getId, request.getId());
            PoiScenario poiScenario = iPoiScenarioService.getBaseMapper().selectOne(wrapper);
            String telephone = poiScenario.getTelephone();
            if (StringUtils.isNotEmpty(request.getKwBossTel()) && !request.getKwBossTel().equals(telephone)) {
                //远程调用接口修改手机号
                if (!flag) {
                    Boolean result = poiDetailClientService.updateTelephone(request.getPoiId(), request.getKwBossTel());
                    log.debug("第一次摸排调用修改手机号结果{}", result);
                }
                telephoneUpdateFlag = true;
            }
        }
        if (flag) {
            //修改数据发送到kafka
            SyncUpdateOrderRequest syncUpdateOrderRequest = new SyncUpdateOrderRequest();
            QKAddressAttr qkAddressAttr = new QKAddressAttr();
            BeanUtils.copyProperties(rgeoAddressVo, qkAddressAttr);
            syncUpdateOrderRequest.setQkAddressAttr(qkAddressAttr);
            syncUpdateOrderRequest.setGdId(request.getPoiId());
            syncUpdateOrderRequest.setPhotos(photos);
            //如果是建筑需要，清空8-11级
            if (isBuild == 1) {
                syncUpdateOrderRequest.getQkAddressAttr().setBuild(null);
                syncUpdateOrderRequest.getQkAddressAttr().setBuildCode(null);
                syncUpdateOrderRequest.getQkAddressAttr().setCell(null);
                syncUpdateOrderRequest.getQkAddressAttr().setCellCode(null);
                syncUpdateOrderRequest.getQkAddressAttr().setFloor(null);
                syncUpdateOrderRequest.getQkAddressAttr().setFloorCode(null);
                syncUpdateOrderRequest.getQkAddressAttr().setRoom(null);
                syncUpdateOrderRequest.getQkAddressAttr().setRoomCode(null);
            }
            if (telephoneUpdateFlag) {
                syncUpdateOrderRequest.setTelephone(request.getKwBossTel());
            }
            log.debug("发送kafka入参{}", JSONUtil.toJsonStr(syncUpdateOrderRequest));
            kafkaProducerService.sendMessage("scenes-order-update", JSONUtil.toJsonStr(syncUpdateOrderRequest));
        }
        log.debug("推送工单返回结果{}", "生成工单成功！");
    }

    //对比8-11级建筑数据
    private boolean updateBuildingInfo(BuildInfo buildInfo, RgeoAddressVo rgeoAddressVo) {
        String build = rgeoAddressVo.getBuild();
        String cell = rgeoAddressVo.getCell();
        String floor = rgeoAddressVo.getFloor();
        String room = rgeoAddressVo.getRoom();
        if (StringUtils.isNotEmpty(build)) {
            build = build.replaceAll("[\\u4e00-\\u9fa5]+", "");
        }
        if (StringUtils.isNotEmpty(cell)) {
            cell = cell.replaceAll("[\\u4e00-\\u9fa5]+", "");
        }
        if (StringUtils.isNotEmpty(floor)) {
            floor = floor.replaceAll("[\\u4e00-\\u9fa5]+", "");
        }
        if (StringUtils.isNotEmpty(room)) {
            room = room.replaceAll("[\\u4e00-\\u9fa5]+", "");
        }
        boolean flagOne = updateField(rgeoAddressVo::setBuild, buildInfo.getBuilding(), build);
        boolean flagTwo = updateField(rgeoAddressVo::setCell, buildInfo.getUnit(), cell);
        boolean flagThree = updateField(rgeoAddressVo::setFloor, buildInfo.getFloor(), floor);
        boolean flagFour = updateField(rgeoAddressVo::setRoom, buildInfo.getRoom(), room);
        return flagOne || flagTwo || flagThree || flagFour;
    }

    //对比5-6级地址
    private boolean updateRoadInfo(PoiKwRequest request, RgeoAddressVo rgeoAddressVo) {
        boolean flagOne = updateField(rgeoAddressVo::setRoad, request.getHouseRoad(), rgeoAddressVo.getRoad());
        String replaceStr = rgeoAddressVo.getRoadNo();
        if (StringUtils.isNotEmpty(rgeoAddressVo.getRoadNo())) {
            replaceStr = rgeoAddressVo.getRoadNo().replaceAll("[\\u4e00-\\u9fa5]+", "");
        }
        boolean flagTwo = updateField(rgeoAddressVo::setRoadNo, request.getHouseNumber(), replaceStr);
        return flagOne || flagTwo;
    }

    //赋值
    private boolean updateField(Consumer<String> setter, String newValue, String currentValue) {
        if (StringUtils.isNotEmpty(newValue) && !newValue.equals(currentValue)) {
            setter.accept(newValue);
            return true;
        }
        return false;
    }

    @Override
    public List<IntentionRecordResponse> selectIntentionRecord(IntentionInfoRequest request) {
        log.debug("意向业务历史记录查询入参，{}", request);
        String serviceTable = ComConstant.TABLES.get(0);
        List<IntentionRecordResponse> responses = iPoiScenarioProofreadService.selectIntentionInfoList(request, serviceTable);
        log.debug("记录数据返回，{}", responses);
        return responses;
    }

    @Override
    @Transactional
    public SpeechTextGetResponse getSpeechText(UploadTextRequest request) {
        String proofreadId = request.getProofreadId();
        log.info("录音接口入参，proofread={}", proofreadId);
        SpeechTextGetResponse speechTextGetResponse = new SpeechTextGetResponse();
        try {
            // 录音文件 上传到minio
            MultipartFile oldFile = request.getFile();

            if (oldFile.getContentType() != null && !oldFile.getContentType().contains("audio")) {
                throw new CommonException("参数[file]传入文件不是音频，请重新检验~");
            }

            // 新建一个新的MultipartFile实例 储存新的流
            MockMultipartFile newFile = new MockMultipartFile(
                    "file", // 参数1：文件名（不含路径）
                    oldFile.getOriginalFilename(), // 参数2：原始文件名
                    oldFile.getContentType(), // 参数3：内容类型
                    new ByteArrayInputStream(oldFile.getBytes()) // 参数4：文件内容
            );

            String uploadMp3 = MinioTool.upload(oldFile);
            String relationId = IdUtil.getSnowflake(1, 1).nextIdStr();
            String id = request.getId();
            Date startTime = request.getStartTime();
            Date endTime = request.getEndTime();
            String timeSlot = request.getTimeSlot();
            //处理录音附件记录
            if (ObjectUtil.isNull(uploadMp3) || uploadMp3.isEmpty()) {
                throw new CommonException("minio服务存放录音音频文件失败~");
            }
            // 处理沿街商铺
            PoiScenarioAppendix speechFile = PoiScenarioAppendix.builder()
                    .poiScenarioId(id)
                    .minioPath(uploadMp3)
                    .type(TypeStatus.AUDIO.getDesc())
                    .startTime(startTime)
                    .endTime(endTime)
                    .createTime(DateUtil.date())
                    .relationId(relationId)
                    .timeSlot(timeSlot)
                    .proofreadId(proofreadId)
                    .build();
            iPoiScenarioAppendixService.save(speechFile);

            speechTextGetResponse.setMp3Path(uploadMp3);
            speechTextGetResponse.setRelationId(relationId);
            speechTextGetResponse.setProofreadId(proofreadId);
        } catch (Exception e) {
            throw new CommonException("录音识别失败：", e);
        }
        log.debug("录音上传接口返回值，{}", speechTextGetResponse);
        return speechTextGetResponse;
    }

    @Override
    public String getSpeech(MultipartFile file) {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpPost httpPost = new HttpPost(convertWordUrl);

        try {
            // 创建MultipartEntityBuilder
            MultipartEntityBuilder builder = MultipartEntityBuilder.create();
            builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);

            // 添加文件部分
            builder.addBinaryBody("file", file.getInputStream(), ContentType.DEFAULT_BINARY, file.getOriginalFilename());

            // 构建并设置实体
            HttpEntity entity = builder.build();
            httpPost.setEntity(entity);

            // 发送请求并获取响应
            HttpResponse response = httpClient.execute(httpPost);
            log.debug("response值：{}", JSONUtil.toJsonStr(response));
            // 处理响应
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode == 200) {
                String responseBody = EntityUtils.toString(response.getEntity());
                log.debug("responseBody值：{}", JSONUtil.toJsonStr(responseBody));
                JSONObject parseObj = JSONUtil.parseObj(responseBody);
                log.debug("parseObj值：{}", JSONUtil.toJsonStr(parseObj));
                String res = parseObj.getByPath("data", String.class);
                log.debug("res:{}", res);
                if (CharSequenceUtil.isNotEmpty(res)) {
                    return res;
                } else {
                    log.debug("调用语音识别接口无果~");
                }
            }

        } catch (Exception e) {
            throw new CommonException(e);
        } finally {
            try {
                httpClient.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        return null;
    }

    @Override
    public void deleteFile(AudioDeleteRequest request) {
        log.debug("录音文件删除入参，{}", request);
        String relationId = request.getRelationId();
        String proofreadId = request.getProofreadId();

        if (StringUtils.isNotEmpty(proofreadId)) {
            QueryWrapper<PoiScenarioAppendix> queryWrapper = new QueryWrapper<>();
            iPoiScenarioAppendixService.remove(queryWrapper.lambda().eq(PoiScenarioAppendix::getRelationId, relationId).eq(PoiScenarioAppendix::getProofreadId, proofreadId));
        }
    }

    @Override
    public List<PoiListResponse> poiQueryByWordNew(QueryByWordRequest request) {
        log.debug("关键字搜索传入的参数，{}", request);
        String location = String.format("POINT(%s %s)", request.getLon(), request.getLat());
        // 判断经纬度是否有效
        if (!isValid(location)) {
            throw new CommonException("经纬度无效");
        }
        List<PoiListResponse> res = Lists.newArrayList();
        PoiListRequest poiListRequest = new PoiListRequest();
        // 沿街商铺搜索
        if (request.getType().contains(ScenesStatus.STREET.getDesc())) {
            List<PoiListResponse> streets = iPoiScenarioChannelService.selectPoiLikeCommon(request, "poi_scenario");
            res.addAll(streets);
        }
        // 五大场景
        if (request.getType().contains(ScenesStatus.BUILD.getDesc())
                || request.getType().contains(ScenesStatus.HOTEL.getDesc())
                || request.getType().contains(ScenesStatus.MARKET.getDesc())
                || request.getType().contains(ScenesStatus.PARK.getDesc())
                || request.getType().contains(ScenesStatus.OTHER.getDesc())) {
            BeanUtils.copyProperties(request, poiListRequest);
            List<PoiListResponse> fives = iPoiScenarioChannelService.selectPoiLikeCommon(request, "poi_scenario");
            res.addAll(fives);
        }
        return res;
    }

    @Override
    public List<IndexAroundResponse> indexQuery(IndexAroundRequest request) {
        log.debug("首页搜索接口传入参数，{}", request);
        BigDecimal rtLon = request.getRtLon();
        BigDecimal rtLat = request.getRtLat();
        BigDecimal lbLon = request.getLbLon();
        BigDecimal lbLat = request.getLbLat();
        BigDecimal lon = request.getLon();
        BigDecimal lat = request.getLat();
        Integer kwState = request.getKwState();

        List<String> code = Lists.newArrayList();
        // 根据当前经纬度获取当前网格
        if (Objects.nonNull(lon) && Objects.nonNull(lat)) {
            code = iExpressRegionService.pointInPolygon(String.format("POINT(%s %s)", lon, lat));
        }
        //如果沒有匹配到网格，则取离着该点最近的
        if (ObjectUtil.isEmpty(code)) {
            log.debug("当前经纬度未匹配到网格数据，{}，{}", lon, lat);
            code = iExpressRegionService.selectCode(lon, lat);
            log.debug("未匹配到网格取离该点最近的网格数据，{}", code);
        }

        QueryWrapper<PoiScenario> streetWrapper = new QueryWrapper<>();
        streetWrapper.lambda().eq(PoiScenario::getKwState, kwState);
        if (Objects.nonNull(rtLon) && Objects.nonNull(rtLat) && Objects.nonNull(lbLon) && Objects.nonNull(lbLat)) {
            streetWrapper.lambda().select(
                    PoiScenario::getId,
                    PoiScenario::getPoiName,
                    PoiScenario::getAddress,
                    PoiScenario::getPoiId,
                    PoiScenario::getPoiLng,
                    PoiScenario::getPoiLat,
                    PoiScenario::getRegionCity,
                    PoiScenario::getRegionDis,
                    PoiScenario::getGridName,
                    PoiScenario::getType
            ).apply(String.format("ST_Within(points,ST_GeomFromText('MULTIPOLYGON(((%s %s,%s %s,%s %s,%s %s,%s %s)))',4326))", lbLon, lbLat, lbLon, rtLat, rtLon, rtLat, rtLon, lbLat, lbLon, lbLat));
            if (ObjectUtil.isNotEmpty(code)) {
                streetWrapper.lambda().in(PoiScenario::getGridCode, code);
            }
        }

        return BeanUtil.copyToList(iPoiScenarioService.list(streetWrapper), IndexAroundResponse.class);
    }

    @SneakyThrows
    @Override
    public void exportScenesExcel(String code) {
        log.debug("开始导出场景攻坚随访明细！");
        String fileName = "随访明细";
        response.setContentType("application/vnd.ms-excel");
        response.setHeader("content-disposition", String.format("attachment;filename=%s.xlsx", new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1) + DateUtil.now()));
        LambdaQueryWrapper<ExpressRegion> expressRegionWrapper = new LambdaQueryWrapper<>();
        expressRegionWrapper.select(ExpressRegion::getLevel).eq(ExpressRegion::getCode, code);
        Integer level = Integer.valueOf(iExpressRegionService.getOne(expressRegionWrapper).getLevel());

        try (ExcelWriter excelWriter = EasyExcelFactory.write(response.getOutputStream()).build()) {
            WriteSheet writeSheet = EasyExcelFactory.writerSheet(0, "随访明细").head(ScenesExportDto.class).build();

            if (2 == level) {
                LambdaQueryWrapper<ExpressRegion> regionQueryWrapper = new LambdaQueryWrapper<>();
                regionQueryWrapper.eq(ExpressRegion::getParentCode, code);
                List<ExpressRegion> expressRegions = iExpressRegionService.list(regionQueryWrapper);
                List<String> disCodes = expressRegions.stream().map(ExpressRegion::getCode).collect(Collectors.toList());
                SyncTool.doSync(disCodes.size(), i -> {
                    List<ScenesExportDto> scenesExportDtoList = iPoiScenarioService.selectCityDetail(disCodes.get(i - 1));
                    scenesExportDtoList.forEach(item -> {
                        if (item.getKwState().equals(ExpressStatus.PROOFED)) {
                            // 导入图片外链
                            item.setPhoto(exportHost + "/display?" + item.getId());
                        }
                    });
                    synchronized (excelWriter) {
                        excelWriter.write(scenesExportDtoList, writeSheet);
                    }
                });
            } else {
                int batchSize = 5000;
                LambdaQueryWrapper<PoiScenario> queryWrapper = new LambdaQueryWrapper<>();

                int count;
                if (level == 3) {
                    queryWrapper.eq(PoiScenario::getRegionDisCode, code);
                    count = iPoiScenarioService.count(queryWrapper);
                } else if (level == 4) {
                    queryWrapper.eq(PoiScenario::getGridCode, code);
                    count = iPoiScenarioService.count(queryWrapper);
                } else {
                    count = 0;
                }

                int pages = count / batchSize + 1;
                SyncTool.doSync(pages, i -> {
                    int startIndex = i == 1 ? 0 : (i - 1) * batchSize;
                    List<ScenesExportDto> scenesExportDtoList = iPoiScenarioService.selectDetailPage(startIndex, batchSize, code, level);
                    scenesExportDtoList.forEach(item -> {
                        if (item.getKwState().equals(ExpressStatus.PROOFED)) {
                            item.setPhoto(exportHost + "display?" + item.getId());
                        }
                    });
                    synchronized (excelWriter) {
                        excelWriter.write(scenesExportDtoList, writeSheet);
                    }
                });
            }
        }
    }

    @Override
    public List<IndexAroundResponse> indexNewQuery(IndexAroundNewRequest request) {
        log.debug("首页可視化区域搜索改造接口传入参数，{}", request);
        String type = request.getType();
        String table = ComConstant.TABLES.get(0);
        Integer level = uniAddrRegionService.selectLevel(request.getCodeStr());
        List<IndexAroundResponse> records = iPoiScenarioService.poiIndexQuery(request, table, level, null);
        if (!type.equals(ScenesStatus.STREET.getDesc())) {
            List<String> collect = records.stream().map(IndexAroundResponse::getPoiId).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(collect)) {
                List<PoiSceneCount> poiSceneCounts = iPoiScenarioService.selectBuildCount(collect);
                //已随访，未随访
                for (IndexAroundResponse record : records) {
                    //替换原数据的商业综合体--->商务楼宇
                    if (ScenesStatus.COMPLEX.getDesc().equals(record.getType())) {
                        record.setType(ScenesStatus.BUSINESS.getDesc());
                    }
                    String poiId = record.getPoiId();
                    int belongOperatorZeroTotal = 0;
                    int belongOperatorTotal = 0;
                    for (PoiSceneCount poiSceneCount : poiSceneCounts) {
                        if (poiId.equals(poiSceneCount.getPoiId())) {
                            //随访个数补充
                            if (poiSceneCount.getKwState() == 1) {
                                record.setKwPoiTotal(record.getKwPoiTotal() + poiSceneCount.getPoiCount());
                            }
                            if (poiSceneCount.getKwState() == 0) {
                                record.setUnKwPoiTotal(record.getUnKwPoiTotal() + poiSceneCount.getPoiCount());
                            }
                            //我网宽带个数
                            if (poiSceneCount.getBelongOperator() != null && poiSceneCount.getBelongOperator().equals(0)) {
                                belongOperatorZeroTotal += poiSceneCount.getPoiCount();
                            }
                            belongOperatorTotal += poiSceneCount.getPoiCount();
                        }
                    }
                    if (belongOperatorTotal != 0) {
                        double result = (double) belongOperatorZeroTotal / belongOperatorTotal;
                        String formattedResult = String.format("%.2f", result);
                        double finalResult = Double.parseDouble(formattedResult);
                        record.setKdRate(finalResult);
                    }
                }
                return records;
            }
        }
        return records;
    }

    @Override
    public List<PoiListResponse> poiSearchByWord(QueryByWordRequest request) {
        log.debug("关键字搜索改造接口传入的参数，{}", request);
        String location = String.format("POINT(%s %s)", request.getLon(), request.getLat());
        // 判断经纬度是否有效
        if (!isValid(location)) {
            throw new CommonException("经纬度无效");
        }
        Integer level = uniAddrRegionService.selectLevel(request.getCodeStr());
        List<PoiListResponse> res = Lists.newArrayList();
        // 沿街商铺搜索
        if (request.getType().contains(ScenesStatus.STREET.getDesc())) {
            List<PoiListResponse> streets = iPoiScenarioChannelService.selectPoiLikeCommonNew(request, "poi_scenario", level);
            res.addAll(streets);
        }
        // 五大场景
        if (request.getType().contains(ScenesStatus.BUSINESS.getDesc())
                || request.getType().contains(ScenesStatus.HOTEL.getDesc())
                || request.getType().contains(ScenesStatus.MARKET.getDesc())
                || request.getType().contains(ScenesStatus.PARK.getDesc())
                || request.getType().contains(ScenesStatus.OTHER.getDesc())) {
            List<PoiListResponse> fives = iPoiScenarioChannelService.selectPoiLikeCommonNew(request, "poi_scenario", level);
            fives.forEach(data -> {
                String type = data.getType();
                if (StringUtils.isNotEmpty(type) && type.equals(ScenesStatus.COMPLEX.getDesc())) {
                    data.setType(ScenesStatus.BUSINESS.getDesc());
                }
            });
            List<PoiListResponse> list = handlerList(request.getType().get(0), fives);
            res.addAll(list);
        }
        return res;
    }

    /**
     * 导出场景攻坚明细--改造
     *
     * @param poiChannelRequest
     */
    @SneakyThrows
    @Override
    public void exportScenesExcelNew(PoiChannelRequest poiChannelRequest) {
        log.debug("导出场景攻坚随访明细改造接口入参，{}", poiChannelRequest);
        String code = poiChannelRequest.getCode();
        String fileName = "随访明细";
        response.setContentType("application/vnd.ms-excel");
        response.setHeader("content-disposition", String.format("attachment;filename=%s.xlsx", new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1) + DateUtil.now()));
        Integer level = uniAddrRegionService.selectLevel(code);
        List<String> headersStr = poiChannelRequest.getHeaders();
        log.debug("传入的导出表头，{}", headersStr);
        List<List<String>> headers = parseHeaderNameNew(headersStr);

        try (ExcelWriter excelWriter = EasyExcelFactory.write(response.getOutputStream()).build()) {
            WriteSheet writeSheet = EasyExcelFactory.writerSheet(0, "随访明细").head(headers).registerWriteHandler(new LongestMatchColumnHandler()).build();
            if (2 == level) {
                List<UniAddrRegion> uniAddrRegionList = uniAddrRegionService.selectRegionListByCode(code);
                List<String> disCodes = uniAddrRegionList.stream().map(UniAddrRegion::getCode).collect(Collectors.toList());
                int finalLevel = level + 1;
                SyncTool.doSync(disCodes.size(), i -> {
                    PoiChannelRequest request = new PoiChannelRequest();
                    BeanUtils.copyProperties(poiChannelRequest, request);
                    request.setCode(disCodes.get(i - 1));
                    List<ScenesPageDto> scenesExportDtoList = iPoiScenarioService.selectDetailCondNewSub(request, ComConstant.TABLES, finalLevel);
                    scenesExportDtoList.forEach(item -> {
                        //处理商业综合体 变为 商务楼宇
                        if (ScenesStatus.COMPLEX.getDesc().equals(item.getType())) {
                            item.setType(ScenesStatus.BUSINESS.getDesc());
                        }
                        if (ScenesStatus.COMPLEX.getDesc().equals(item.getKwType())) {
                            item.setKwType(ScenesStatus.BUSINESS.getDesc());
                        }
                        if (item.getKwState().equals(ExpressStatus.PROOFED)) {
                            if (!StringUtils.isEmpty(item.getType()) && "沿街商铺".equals(item.getType())) {
                                // 导入图片外链 0代表沿街
                                item.setPhoto(exportHost + "scenesDisplay?" + "id=" + item.getId() + "&type=0" + "&proofreadId=" + item.getProofreadId());
                            } else if (!StringUtils.isEmpty(item.getType())) {
                                item.setPhoto(exportHost + "scenesDisplay?" + "id=" + item.getId() + "&type=1" + "&proofreadId=" + item.getProofreadId());
                            }
                        }
                        //对勘误之后的状态 poi名称和type进行处理
                        if (StringUtils.isEmpty(item.getKwType()) || item.getType().equals(item.getKwType())) {
                            item.setKwType(item.getType());
                        }
                        if (StringUtils.isEmpty(item.getKwPoiName()) || item.getPoiName().equals(item.getKwPoiName())) {
                            item.setKwPoiName(item.getPoiName());
                        }
                    });
                    List<Object> maps = filterColumns(scenesExportDtoList, headersStr);
                    synchronized (excelWriter) {
                        excelWriter.write(maps, writeSheet);
                    }
                });
            } else {
                int batchSize = 5000;
                int result = iPoiScenarioService.selectDetailCountNew(poiChannelRequest, ComConstant.TABLES.get(0), level);
                int pages = result / batchSize + 1;
                SyncTool.doSync(pages, i -> {
                    int startIndex = (i - 1) * batchSize;
                    PoiChannelRequest request = new PoiChannelRequest();
                    BeanUtils.copyProperties(poiChannelRequest, request);
                    request.setPageNo(startIndex);
                    request.setPageSize(batchSize);
                    poiChannelRequest.setPageNo(startIndex);
                    poiChannelRequest.setPageSize(batchSize);
                    List<ScenesPageDto> scenesExportDtoList = iPoiScenarioService.selectDetailCondPageNew(request, ComConstant.TABLES, level);
                    scenesExportDtoList.forEach(item -> {
                        //处理商业综合体 变为 商务楼宇
                        if (ScenesStatus.COMPLEX.getDesc().equals(item.getType())) {
                            item.setType(ScenesStatus.BUSINESS.getDesc());
                        }
                        if (ScenesStatus.COMPLEX.getDesc().equals(item.getKwType())) {
                            item.setKwType(ScenesStatus.BUSINESS.getDesc());
                        }
                        if (item.getKwState().equals(ExpressStatus.PROOFED)) {
                            if (!StringUtils.isEmpty(item.getType()) && "沿街商铺".equals(item.getType())) {
                                // 导入图片外链 0代表沿街
                                item.setPhoto(exportHost + "scenesDisplay?" + "id=" + item.getId() + "&type=0" + "&proofreadId=" + item.getProofreadId());
                            } else if (!StringUtils.isEmpty(item.getType())) {
                                item.setPhoto(exportHost + "scenesDisplay?" + "id=" + item.getId() + "&type=1" + "&proofreadId=" + item.getProofreadId());
                            }
                        }
                        //对勘误之后状态 poi名称和type进行处理
                        if (StringUtils.isEmpty(item.getKwType()) || item.getType().equals(item.getKwType())) {
                            item.setKwType(item.getType());
                        }
                        if (StringUtils.isEmpty(item.getKwPoiName()) || item.getPoiName().equals(item.getKwPoiName())) {
                            item.setKwPoiName(item.getPoiName());
                        }
                    });
                    List<Object> maps = filterColumns(scenesExportDtoList, headersStr);
                    synchronized (excelWriter) {
                        excelWriter.write(maps, writeSheet);
                    }
                });
            }
        }
    }

    private List<List<String>> parseHeaderNameNew(List<String> headers) {
        ArrayList<List<String>> list = new ArrayList<>();
        for (String column : headers) {
            Field field = null;
            try {
                field = ScenesPageDto.class.getDeclaredField(column);
                String value = field.getName();
                if (column.equals(value)) {
                    ExcelProperty annotation = field.getAnnotation(ExcelProperty.class);
                    if (annotation != null) {
                        String name = annotation.value()[0];
                        List<String> listName = ImmutableList.of(name);
                        list.add(listName);
                    } else {
                        List<String> listName = ImmutableList.of(column);
                        list.add(listName);
                    }
                }
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            }
        }
        return list;
    }

    //筛选出只需要导出的字段值
    private List<Object> filterColumns(List<ScenesPageDto> dataList, List<String> columnsToExport) {
        List<Object> filteredData = new ArrayList<>();
        for (ScenesPageDto dto : dataList) {
            List<Object> row = new ArrayList<>();
            for (String column : columnsToExport) {
                try {
                    // 获取字段对象
                    Field field = ScenesPageDto.class.getDeclaredField(column);
                    // 设置字段可访问
                    field.setAccessible(true);
                    Object value = field.get(dto);

                    // 检查字段是否有ExcelProperty注解
                    ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class);
                    if (excelProperty != null) {
                        // 获取并应用转换器
                        Class<? extends Converter<?>> converterClass = excelProperty.converter();
                        try {
                            if (converterClass == CustomEnumConverter.class || converterClass == OperatorConverter.class || converterClass == BusinessStateConverter.class) {
                                @SuppressWarnings("unchecked")
                                Converter<Object> converter = (Converter<Object>) converterClass.getDeclaredConstructor().newInstance();
                                // 创建ExcelContentProperty对象
                                value = converter.convertToExcelData(value, null, null);
                            }
                            if (converterClass == DatetimeConverter.class) {
                                ExcelContentProperty contentProperty = new ExcelContentProperty();
                                contentProperty.setField(field);
                                @SuppressWarnings("unchecked")
                                Converter<Date> converter = (Converter<Date>) converterClass.getDeclaredConstructor().newInstance();
                                Date date = (Date) value;
                                // 将日期格式化为字符串
                                // 创建ExcelContentProperty对象
                                value = converter.convertToExcelData(date, contentProperty, null);
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }

                    row.add(value != null ? value : "");
                } catch (NoSuchFieldException | IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
            filteredData.add(row);
        }
        return filteredData;
    }

    @Override
    public IPage<ScenesPageDto> selectDetailPage(Integer pageNo, Integer pageSize, String code, String kwPhone, Integer kwState) {
        LambdaQueryWrapper<ExpressRegion> expressRegionWrapper = new LambdaQueryWrapper<>();
        expressRegionWrapper.select(ExpressRegion::getLevel).eq(ExpressRegion::getCode, code);
        Integer level = Integer.valueOf(iExpressRegionService.getOne(expressRegionWrapper).getLevel());
        int count = iPoiScenarioService.selectDetailCount(code, level, kwPhone, kwState);
        int startIndex = pageNo == 1 ? 0 : (pageNo - 1) * pageSize;
        int batchSize = pageSize;
        List<ScenesPageDto> scenesExportDtoList = iPoiScenarioService.selectDetailCondPage(startIndex, batchSize, code, level, kwPhone, kwState);
        IPage<ScenesPageDto> res = new Page<>();
        res.setTotal(count);
        res.setRecords(scenesExportDtoList);
        res.setCurrent(pageNo);
        res.setSize(pageSize);
        return res;
    }

    @Override
    public List<String> showPhoto(String id, Integer type, String proofreadId) {
        log.debug("图片查看传入参数，id={}，type={}，proofreadId={}", id, type, proofreadId);
        List<String> base64Infos = Lists.newArrayList();
        //0是沿街商鋪
        QueryWrapper<PoiScenarioAppendix> poiStreetAppendixQueryWrapper = new QueryWrapper<>();
        poiStreetAppendixQueryWrapper.lambda().
                select(PoiScenarioAppendix::getMinioPath, PoiScenarioAppendix::getType).
                eq(PoiScenarioAppendix::getProofreadId, proofreadId).
                eq(PoiScenarioAppendix::getPoiScenarioId, id);
        List<PoiScenarioAppendix> minIoPaths = iPoiScenarioAppendixService.list(poiStreetAppendixQueryWrapper);
        if (ObjectUtil.isNotEmpty(minIoPaths)) {
            minIoPaths.forEach(item -> {
                if (TypeStatus.PHOTO.getDesc().equals(item.getType())) {
                    // 转换成 base64
                    byte[] imageBytes = new byte[0];
                    try {
                        imageBytes = MinioTool.fetchLocalBytes(item.getMinioPath());
                    } catch (Exception e) {
                        log.debug("minio服务解析图片返回byte数组失败~");
                    }
                    if (imageBytes != null && imageBytes.length > 0) {
                        String base64Image = BASE64_HEADER + DatatypeConverter.printBase64Binary(imageBytes);
                        if (CharSequenceUtil.isNotEmpty(base64Image)) {
                            base64Infos.add(base64Image);
                        }
                    }
                }
            });
        }
        return base64Infos;
    }

    @Override
    public List<String> queryPhoto(String id) {
        log.debug("政企建档调用照片查询接口入参，id={}", id);
        List<String> base64Infos = Lists.newArrayList();
        //查询沿街表
        QueryWrapper<PoiScenarioProofread> proofreadQueryWrapper = new QueryWrapper<>();
        proofreadQueryWrapper.lambda().select(PoiScenarioProofread::getId).eq(PoiScenarioProofread::getPoiScenarioId, id).orderByDesc(PoiScenarioProofread::getKwTime).last("limit 1");
        PoiScenarioProofread poiScenarioProofread = iPoiScenarioProofreadService.getBaseMapper().selectOne(proofreadQueryWrapper);
        if (poiScenarioProofread != null) {
            QueryWrapper<PoiScenarioAppendix> poiStreetAppendixQueryWrapper = new QueryWrapper<>();
            poiStreetAppendixQueryWrapper.lambda().
                    select(PoiScenarioAppendix::getMinioPath, PoiScenarioAppendix::getType).
                    eq(PoiScenarioAppendix::getProofreadId, poiScenarioProofread.getId()).
                    eq(PoiScenarioAppendix::getType, TypeStatus.PHOTO.getDesc()).
                    eq(PoiScenarioAppendix::getPoiScenarioId, id);
            List<PoiScenarioAppendix> minIoPaths = iPoiScenarioAppendixService.list(poiStreetAppendixQueryWrapper);
            if (ObjectUtil.isNotEmpty(minIoPaths)) {
                minIoPaths.forEach(item -> {
                    if (TypeStatus.PHOTO.getDesc().equals(item.getType())) {
                        // 转换成 base64
                        byte[] imageBytes = new byte[0];
                        try {
                            imageBytes = MinioTool.fetchLocalBytes(item.getMinioPath());
                        } catch (Exception e) {
                            log.debug("政企建档,minio服务解析图片返回byte数组失败~");
                        }
                        if (imageBytes != null && imageBytes.length > 0) {
                            String base64Image = BASE64_HEADER + DatatypeConverter.printBase64Binary(imageBytes);
                            if (CharSequenceUtil.isNotEmpty(base64Image)) {
                                base64Infos.add(base64Image);
                            }
                        }
                    }
                });
            }
        }
        return base64Infos;
    }

    @Override
    public DefaultPermissionsResponse getDefaultData() {
        DefaultPermissionsResponse response = new DefaultPermissionsResponse();
        if ("local".equals(env)||!ssoValid && Objects.requireNonNull(SystemUtil.getCurrentUser()).getUsername().equals("root")) {
            response.setName("济南").setCode("SD.LA");
            return response;
        }
        LoginUser currentUser = SystemUtil.getCurrentUser();
        if (ObjectUtil.isNull(currentUser)) {
            throw new CommonException("解析用户失败");
        }
        // 调用华为直连网格 - 根据工号返回相应业务区域
        HwGetGridIdRequest request = new HwGetGridIdRequest();
        request.setCrmAccount(currentUser.getUsername());
        request.setType("3");
        List<HwGridByNumResponse> responseList = hwRestApiService.getGridByAccountTest(request);
        if (ObjectUtil.isNotEmpty(responseList)) {
            HwGridByNumResponse collect = responseList.stream().sorted(Comparator.comparing(HwGridByNumResponse::getAreaCode)).min(Comparator.comparingInt(item -> item.getAllParentCode().split(",").length)).orElse(HwGridByNumResponse.builder().build());
            if ("SD".equals(collect.getAreaCode())) {
                response.setCode("SD.LA").setName("济南");
            } else {
                response.setCode(collect.getAreaCode()).setName(collect.getAreaName());
            }
        }
        return response;
    }

    @Override
    public BusResponse businessByPhone(String phone) {

        if (Boolean.TRUE.equals(jfEnabled)) {
            log.debug("开始调用【根据手机号获取业务信息】接口");
            HttpClient httpClient = HttpClients.createDefault();
            // 发起请求并获取响应
            HttpGet httpGet = new HttpGet(String.format("%s:8080/dataex/api/getMobilewireInfoByServnumber?timestamp=20240603&signature=9cf1405ca6c9b93d256eed80824cb79a3322c9392747ddec16e74df2a5e6c3ee&appKey=aibass&servnumber=%s", jfUrl, phone));

            try {
                HttpResponse httpResponse = httpClient.execute(httpGet);
                if (ObjectUtil.isNotEmpty(httpResponse)) {
                    int statusCode = httpResponse.getStatusLine().getStatusCode();
                    // 处理响应
                    if (statusCode == 200) {
                        String responseBody = EntityUtils.toString(httpResponse.getEntity());
                        if (CharSequenceUtil.isNotEmpty(responseBody)) {
                            responseBody = responseBody.replace("  ", "");
                            if (ObjectUtil.isNotEmpty(responseBody)) {
                                JSONArray jsonArray = JSONUtil.parseArray(responseBody);
                                if (jsonArray.isEmpty()) {
                                    return null;
                                }
                                String res = JSONUtil.parseObj(jsonArray.get(0)).toString();
                                return JSONUtil.parseObj(res).toBean(BusResponse.class);
                            } else {
                                log.debug("调用手机号获取业务信息接口无果~");
                            }
                        }

                    }
                }
                return null;

            } catch (Exception e) {
                log.error("调用【根据手机号获取业务信息】接口异常~");
                throw new CommonException("调用【根据手机号获取业务信息】接口异常");
            } finally {
                httpClient.getConnectionManager().shutdown();
            }
        } else {
            return BusResponse.builder()
                    .CONSUME(48.233333)
                    .OPERATOR("移动")
                    .BANDPROCESS("是")
                    .BANDTYPE("家宽")
                    .BANDADDRESS("测试地址")
                    .EXPIRETIME("2024-04-29 13:32:48")
                    .build();
        }

    }

    @Override
    public Boolean checkPhone(String phone, String channelCode) {
        return iPoiScenarioChannelService.selectCountByPhone(phone, channelCode) > 0;
    }

    @Override
    public IPage<ScenesPageDto> selectDetailPageNew(PoiSearchRequest poiSearchRequest) {
        log.debug("摸排后台数据传入的参数，{}", poiSearchRequest);
        PoiChannelRequest poiChannelRequest = new PoiChannelRequest();
        BeanUtils.copyProperties(poiSearchRequest, poiChannelRequest);
        String code = poiChannelRequest.getCode();
        Integer pageNo = poiChannelRequest.getPageNo();
        Integer pageSize = poiChannelRequest.getPageSize();
        Integer level = uniAddrRegionService.selectLevel(code);
        int result = iPoiScenarioService.selectDetailCountNew(poiChannelRequest, ComConstant.TABLES.get(0), level);
        int offset = (pageNo - 1) * pageSize;
        poiChannelRequest.setPageNo(offset);
        List<ScenesPageDto> scenesExportDtoList = iPoiScenarioService.selectDetailCondPageNew(poiChannelRequest, ComConstant.TABLES, level);
        //处理商业综合体 变为 商务楼宇
        if (CollectionUtils.isNotEmpty(scenesExportDtoList)) {
            scenesExportDtoList.forEach(scenesPageDto -> {
                if (ScenesStatus.COMPLEX.getDesc().equals(scenesPageDto.getType())) {
                    scenesPageDto.setType(ScenesStatus.BUSINESS.getDesc());
                }
                if (ScenesStatus.COMPLEX.getDesc().equals(scenesPageDto.getKwType())) {
                    scenesPageDto.setKwType(ScenesStatus.BUSINESS.getDesc());
                }
            });
        }
        IPage<ScenesPageDto> res = new Page<>();
        res.setTotal(result);
        res.setRecords(scenesExportDtoList);
        res.setCurrent(pageNo);
        res.setSize(pageSize);
        return res;
    }

    /**
     * 导出excel模板
     */
    @Override
    public void modelDownload(HttpServletResponse response) {
        try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
            // 设置响应头信息
            response.setContentType(MediaType.APPLICATION_OCTET_STREAM.toString());
            response.setCharacterEncoding(StandardCharsets.UTF_8.name());
            String fileName = URLEncoder.encode("人员导入模板.csv", StandardCharsets.UTF_8.toString());
            response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
            List<PoiChannelModel> emptyDataList = new ArrayList<>();
            EasyExcel.write(outputStream, PoiChannelModel.class)
                    .sheet("人员导入模板")
                    .doWrite(emptyDataList);
            // 将内存中的CSV数据写入到响应输出流
            outputStream.writeTo(response.getOutputStream());
            response.flushBuffer();
        } catch (Exception e) {
            log.debug("导出excel人员模板失败！");
            e.printStackTrace();
        }
    }

    @Override
    public PoiInfoDetailResponse selectPoiInfoDetail(PoiInfoDetailRequest poiInfoDetailRequest) {
        log.debug("poi点位名称详情入参，{}", poiInfoDetailRequest);
//        String serviceTable = ScenesStatus.STREET.equals(fromDescription(poiInfoDetailRequest.getType())) ? "poi_scenario" : "poi_five";
        PoiInfoDetailResponse response = iPoiScenarioService.queryPoiInfoDetailById(poiInfoDetailRequest, "poi_scenario");
        if (response == null) {
            throw new CommonException("未查询到数据");
        }

        //替换 商业综合体 为 商务楼宇
        if (!StringUtils.isEmpty(response.getType()) && response.getType().equals(ScenesStatus.COMPLEX.getDesc())) {
            response.setType(ScenesStatus.BUSINESS.getDesc());
        }
        if (!StringUtils.isEmpty(response.getKwType()) && response.getKwType().equals(ScenesStatus.COMPLEX.getDesc())) {
            response.setKwType(ScenesStatus.BUSINESS.getDesc());
        }
        if (ObjectUtil.isNotEmpty(response)) {
            if (StringUtils.isNotEmpty(response.getKwRelativesInfo())) {
                List<KwRelativesDto> kwRelativesList = JSON.parseArray(response.getKwRelativesInfo(), KwRelativesDto.class);
                response.setKwRelationInfoList(kwRelativesList);
            }
            // 商机内容（录音识别）
            if (StringUtils.isNotEmpty(response.getContentList())) {
                List<BusContentDto> busContentDtoList = JSON.parseArray(response.getContentList(), BusContentDto.class);
                response.setBusinessContentList(busContentDtoList);
            }
            if (CharSequenceUtil.isNotEmpty(response.getType())) {
                QueryWrapper<PoiScenarioAppendix> poiStreetAppendixQueryWrapper = new QueryWrapper<>();
                poiStreetAppendixQueryWrapper.lambda().eq(PoiScenarioAppendix::getPoiScenarioId, poiInfoDetailRequest.getId()).eq(PoiScenarioAppendix::getProofreadId, poiInfoDetailRequest.getProofreadId()).orderByDesc(PoiScenarioAppendix::getCreateTime);
                response.setAppendixInfos(BeanUtil.copyToList(iPoiScenarioAppendixService.list(poiStreetAppendixQueryWrapper), AppendixResponse.class));
            }
        }
        // 进行base64字符串返回
        if (ObjectUtil.isNotEmpty(response.getAppendixInfos())) {
            List<ImageResponse> base64Infos = Lists.newArrayList();
            response.getAppendixInfos().forEach(item -> {
                if (TypeStatus.PHOTO.getDesc().equals(item.getType())) {
                    byte[] imageBytes = new byte[0];
                    try {
                        imageBytes = MinioTool.fetchLocalBytes(item.getMinioPath());
                    } catch (Exception e) {
                        log.debug("minio服务解析图片返回byte数组失败~");
                    }
                    if (imageBytes != null && imageBytes.length > 0) {
                        String base64Image = BASE64_HEADER + DatatypeConverter.printBase64Binary(imageBytes);
                        if (CharSequenceUtil.isNotEmpty(base64Image)) {
                            base64Infos.add(ImageResponse.builder()
                                    .minioPath(item.getMinioPath())
                                    .base64(base64Image)
                                    .build());
                        }
                    }
                }
            });
            response.setBase64Infos(base64Infos.stream()
                    .sorted(Comparator.comparing(
                            obj -> obj.getMinioPath().split("_")[obj.getMinioPath().split("_").length - 1]
                    )).collect(Collectors.toList()));
        }
        return response;
    }

    @Override
    public void peopleExcelImport(MultipartFile file) {
        boolean flag = poiUserPermissionService.hasPermission();
        if (!flag) {
            throw new CommonException("当前工号没有权限操作");
        }
        if (file == null || file.isEmpty()) {
            throw new CommonException("传入文件为空！");
        }
        log.debug("进入责任人导出方法，文件大小，{}", file.getSize());
        try {
            InputStream inputStream = file.getInputStream();
            iPoiNumberInfoService.processFile(inputStream);
        } catch (IOException e) {
            log.debug("文件导入出现问题！");
            e.printStackTrace();
        }
    }

    /**
     * 返回用户的角色列表
     *
     * @param decryptedMap
     * @return
     */
    @Override
    public List<RoleInfoResponse> areaPermissionByNumNew(TreeMap<String, String> decryptedMap) {
        log.debug("获取角色信息列表请求参数，{}", decryptedMap);
        String telNum = decryptedMap.get("telNum");
        if (CharSequenceUtil.isBlank(telNum)) {
            throw new CommonException("工号不能为空！！");
        }
        //获取工号
        HwGetGridIdRequest request = new HwGetGridIdRequest();
        request.setType("3");
        request.setCrmAccount(telNum);
        List<HwGridByNumResponse> responseList = null;
        ArrayList<RoleInfoResponse> roleList = new ArrayList<>();
        //生产环境调用 判断省市区网格权限
        if (ssoValid) {
            responseList = hwRestApiService.getGridByAccountTest(request);
            log.debug("调用华为接口返回的数据列表，{}", responseList);
        } else {
            RoleInfoResponse roleInfoResponse0 = new RoleInfoResponse();
            roleInfoResponse0.setCodeStr("SD");
            roleInfoResponse0.setRoleType(RoleCodeEnum.ONE.getCode());
            roleInfoResponse0.setRoleName(RoleCodeEnum.ONE.getValue() + ":" + "山东");
            roleInfoResponse0.setGridType(RegionNumPermissionEnum.PROVINCE.name());
            roleInfoResponse0.setRegionName("山东");
            roleInfoResponse0.setRegionCode("SD");
            roleList.add(roleInfoResponse0);
            RoleInfoResponse roleInfoResponse = new RoleInfoResponse();
            roleInfoResponse.setCodeStr("SD.LA");
            roleInfoResponse.setRoleType(RoleCodeEnum.TWO.getCode());
            roleInfoResponse.setRoleName(RoleCodeEnum.TWO.getValue() + ":" + "山东-济南");
            roleInfoResponse.setGridType(RegionNumPermissionEnum.CITY.name());
            roleInfoResponse.setRegionName("山东-济南");
            roleInfoResponse.setRegionCode("SD,SD.LA");
            roleList.add(roleInfoResponse);
            RoleInfoResponse roleInfoResponse3 = new RoleInfoResponse();
            roleInfoResponse3.setCodeStr("SD.LA.0d");
            roleInfoResponse3.setRoleType(RoleCodeEnum.THREE.getCode());
            roleInfoResponse3.setRoleName(RoleCodeEnum.THREE.getValue() + ":" + "山东-济南-市中区");
            roleInfoResponse3.setGridType(RegionNumPermissionEnum.DISTRICT.name());
            roleInfoResponse3.setRegionName("山东-济南-市中区");
            roleInfoResponse3.setRegionCode("SD,SD.LA,SD.LA.0d");
            roleList.add(roleInfoResponse3);
            RoleInfoResponse roleInfoResponse2 = new RoleInfoResponse();
            roleInfoResponse2.setGridType(RegionNumPermissionEnum.GRID.name());
            roleInfoResponse2.setCodeStr("531.0014.d02");
            roleInfoResponse2.setRoleType(RoleCodeEnum.FOUR.getCode());
            roleInfoResponse2.setRoleName(RoleCodeEnum.FOUR.getValue() + ":" + "山东-济南-市中区-共青大观园社区网格");
            roleInfoResponse2.setRegionName("山东-济南-市中区-共青大观园社区网格");
            roleInfoResponse2.setRegionCode("SD,SD.LA,SD.LA.0d,531.0014.d02");
            roleList.add(roleInfoResponse2);
        }
        //判断省市区网格角色权限
        if (CollectionUtils.isNotEmpty(responseList)) {
            List<HwGridByNumResponse> newResponseList = responseList.stream().filter(item -> StringUtils.isNotEmpty(item.getAreaCode()) &&
                    StringUtils.isNotEmpty(item.getAllParentCode()) && StringUtils.isNotEmpty(item.getFullName())).collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(HwGridByNumResponse::getAreaCode))), ArrayList::new));
            if (CollectionUtils.isNotEmpty(newResponseList)) {
                for (HwGridByNumResponse response : newResponseList) {
                    String[] areaCode = response.getAllParentCode().split(",");
                    String[] fullName = response.getFullName().split("-");
                    if (areaCode.length != fullName.length) {
                        continue;
                    }
                    RoleInfoResponse roleInfoResponse = new RoleInfoResponse();
                    roleInfoResponse.setCodeStr(response.getAreaCode());
                    roleInfoResponse.setRegionName(response.getFullName());
                    roleInfoResponse.setRegionCode(response.getAllParentCode());
                    //省
                    if (areaCode.length == 1) {
                        roleInfoResponse.setGridType(RegionNumPermissionEnum.PROVINCE.name());
                        roleInfoResponse.setRoleType(RoleCodeEnum.ONE.getCode());
                        roleInfoResponse.setRoleName(RoleCodeEnum.ONE.getValue() + ":" + response.getFullName());
                        //市
                    } else if (areaCode.length == 2) {
                        roleInfoResponse.setGridType(RegionNumPermissionEnum.CITY.name());
                        roleInfoResponse.setRoleType(RoleCodeEnum.TWO.getCode());
                        roleInfoResponse.setRoleName(RoleCodeEnum.TWO.getValue() + ":" + response.getFullName());
                        //区
                    } else if (areaCode.length == 3) {
                        roleInfoResponse.setGridType(RegionNumPermissionEnum.DISTRICT.name());
                        roleInfoResponse.setRoleType(RoleCodeEnum.THREE.getCode());
                        roleInfoResponse.setRoleName(RoleCodeEnum.THREE.getValue() + ":" + response.getFullName());
                        //网格
                    } else if (areaCode.length == 4) {
                        roleInfoResponse.setGridType(RegionNumPermissionEnum.GRID.name());
                        roleInfoResponse.setGridId(response.getAreaCode());
                        roleInfoResponse.setRoleType(RoleCodeEnum.FOUR.getCode());
                        roleInfoResponse.setRoleName(RoleCodeEnum.FOUR.getValue() + ":" + response.getFullName());
                    }
                    roleList.add(roleInfoResponse);
                }
            }

        }
        //判断是否是渠道角色权限
        if (!StringUtils.isEmpty(decryptedMap.get("channelCode"))) {
            for (int index = 0; index < ComConstant.TABLES.size(); index++) {
                String table = ComConstant.TABLES.get(index);
                List<UnFollowPoiDto> list = iPoiScenarioChannelService.selectGridCodeList(decryptedMap.get("channelCode"), null, null, table);
                if (CollectionUtils.isNotEmpty(list)) {
                    UnFollowPoiDto poiDto = list.get(0);
                    RoleInfoResponse roleInfoResponse = new RoleInfoResponse();
                    roleInfoResponse.setGridType(RegionNumPermissionEnum.UN_PROVINCE.name());
                    roleInfoResponse.setRoleType(RoleCodeEnum.FIVE.getCode());
                    roleInfoResponse.setRoleName(RoleCodeEnum.FIVE.getValue() + ":" + decryptedMap.get("channelCode"));
                    roleInfoResponse.setRegionCode("SD," + poiDto.getRegionCityCode() + "," + poiDto.getRegionDisCode() + "," + poiDto.getGridCode());
                    roleInfoResponse.setRegionName("山东-" + poiDto.getRegionCity() + "-" + poiDto.getGridName());
                    roleInfoResponse.setChannelCode(decryptedMap.get("channelCode"));
                    roleInfoResponse.setCodeStr(poiDto.getGridCode());
                    roleList.add(roleInfoResponse);
                    break;
                }
            }
        }
        //判断是否是自有人员角色权限
        for (int index = 0; index < ComConstant.TABLES.size(); index++) {
            String table = ComConstant.TABLES.get(index);
            List<UnFollowPoiDto> list = iPoiScenarioChannelService.selectGridCodeList(null, null, telNum, table);
            if (CollectionUtils.isNotEmpty(list)) {
                UnFollowPoiDto poiDto = list.get(0);
                RoleInfoResponse roleInfoResponse = new RoleInfoResponse();
                roleInfoResponse.setRoleType(RoleCodeEnum.SIX.getCode());
                roleInfoResponse.setRoleName(RoleCodeEnum.SIX.getValue());
                roleInfoResponse.setRegionCode("SD," + poiDto.getRegionCityCode() + "," + poiDto.getRegionDisCode() + "," + poiDto.getGridCode());
                roleInfoResponse.setRegionName("山东-" + poiDto.getRegionCity() + "-" + poiDto.getGridName());
                roleInfoResponse.setTelNum(telNum);
                roleInfoResponse.setCodeStr(poiDto.getGridCode());
                roleList.add(roleInfoResponse);
                break;
            }
        }
        //判断直销人员权限
        for (int index = 0; index < ComConstant.TABLES.size(); index++) {
            String table = ComConstant.TABLES.get(index);
            List<UnFollowPoiDto> list = iPoiScenarioChannelService.selectGridCodeList(null, telNum, null, table);
            if (CollectionUtils.isNotEmpty(list)) {
                UnFollowPoiDto poiDto = list.get(0);
                RoleInfoResponse roleInfoResponse = new RoleInfoResponse();
                roleInfoResponse.setRoleType(RoleCodeEnum.SEVEN.getCode());
                roleInfoResponse.setRoleName(RoleCodeEnum.SEVEN.getValue());
                roleInfoResponse.setRegionCode("SD," + poiDto.getRegionCityCode() + "," + poiDto.getRegionDisCode() + "," + poiDto.getGridCode());
                roleInfoResponse.setRegionName("山东-" + poiDto.getRegionCity() + "-" + poiDto.getGridName());
                roleInfoResponse.setTelNum(telNum);
                roleInfoResponse.setCodeStr(poiDto.getGridCode());
                roleList.add(roleInfoResponse);
                break;
            }
        }
        log.debug("返回的角色列表信息，{}", roleList);
        return roleList;
    }

    @Override
    public Result<?> peopleExcelImportVerify(MultipartFile file) {
        boolean flag = poiUserPermissionService.hasPermission();
        if (!flag) {
            throw new CommonException("当前工号没有权限操作");
        }
        InputStream inputStream = null;
        final int[] insertTotal = {0};
        final int[] updateTotal = {0};
        //其他场景
        HashSet<PoiChannelModel> poiFiveChannelSet = new HashSet<>();
        //沿街
        HashSet<PoiChannelModel> poiStreetChannelSet = new HashSet<>();
        HashSet<String> poiIdSet = new HashSet<>();
        HashSet<String> repeatSet = new HashSet<>();
        try {
            inputStream = file.getInputStream();
            EasyExcel.read(inputStream, PoiChannelModel.class, new AnalysisEventListener<PoiChannelModel>() {
                @Override
                public void invoke(PoiChannelModel data, AnalysisContext context) {
                    int rowIndex = context.readRowHolder().getRowIndex() + 1;
                    //校验 type是不是空，
                    if (StringUtils.isEmpty(data.getType())) {
                        poiFiveChannelSet.clear();
                        poiStreetChannelSet.clear();
                        throw new CommonException("第" + rowIndex + "行，场景类型列不能为空！");
                    }
                    //校验 poiId 是否为空
                    if (StringUtils.isEmpty(data.getPoiId())) {
                        poiFiveChannelSet.clear();
                        poiStreetChannelSet.clear();
                        throw new CommonException("第" + rowIndex + "行，POI_ID列不能为空！");
                    }
                    //校验 type的名称是否正确
                    if (!ScenesStatus.verifyName(data.getType())) {
                        poiFiveChannelSet.clear();
                        poiStreetChannelSet.clear();
                        throw new CommonException("第" + rowIndex + "行，场景类型列值有误！");
                    }
                    //校验poiId是否重复
                    if (!poiIdSet.add(data.getPoiId())) {
                        repeatSet.add(data.getPoiId());
                    }
                    if (data.getType().equals("沿街商铺")) {
                        poiStreetChannelSet.add(data);
                        //其他场景
                    } else {
                        poiFiveChannelSet.add(data);
                    }
                }

                //读取完集合需要去判断新增和更新的条数给前端返回
                @Override
                public void doAfterAllAnalysed(AnalysisContext context) {
                    if (CollectionUtils.isNotEmpty(repeatSet)) {
                        throw new CommonException("下述poiId值重复：" + repeatSet);
                    }
                    AtomicInteger updateStreetCount = new AtomicInteger();
                    AtomicInteger updateFiveCount = new AtomicInteger();
                    //沿街集合
                    ArrayList<PoiChannelModel> poiStreetList = new ArrayList<>(poiStreetChannelSet);
                    int streetChannelSize = poiStreetList.size();
                    //其他场景集合
                    ArrayList<PoiChannelModel> poiFiveList = new ArrayList<>(poiFiveChannelSet);
                    int fiveChannelSize = poiFiveList.size();
                    //取最大的一个数
                    int maxSize = Math.max(streetChannelSize, fiveChannelSize);
                    int batchSize = 3000;
                    int streetSize = (int) Math.ceil((double) streetChannelSize / batchSize);
                    int fiveSize = (int) Math.ceil((double) fiveChannelSize / batchSize);
                    int num = (int) Math.ceil((double) maxSize / batchSize);
                    CopyOnWriteArrayList<String> copyOnWriteArrayList = new CopyOnWriteArrayList<>();
                    //校验poiId在表里是否存在
                    SyncTool.doSync(num, i -> {
                        int startIndex = (i - 1) * batchSize;
                        int endStreetIndex = Math.min(batchSize * i, streetChannelSize);
                        int endFiveIndex = Math.min(batchSize * i, fiveChannelSize);
                        if (endStreetIndex > 0 && endStreetIndex <= streetChannelSize && num <= streetSize) {
                            List<String> subList = poiStreetList.stream().map(PoiChannelModel::getPoiId).collect(Collectors.toList()).subList(startIndex, endStreetIndex);
                            List<String> list = iPoiScenarioChannelService.hasExistPoiId(subList);
                            copyOnWriteArrayList.addAll(list);
                        }
                    });
                    if (!copyOnWriteArrayList.isEmpty()) {
                        throw new CommonException("原数据不包含下述poiId" + copyOnWriteArrayList);
                    }
                    //首先校验沿街的不应该填建筑poiId
                    List<PoiChannelModel> collect = poiStreetList.stream().filter(entity -> entity.getBelongBuildId() != null).collect(Collectors.toList());
                    if (!CollectionUtils.isEmpty(collect) && collect.size() > 0) {
                        List<String> poiIdList = collect.stream().map(PoiChannelModel::getPoiId).collect(Collectors.toList());
                        throw new CommonException("下述企业poiId没有建筑poiId" + poiIdList);
                    }
                    //校验poi是否有归属建筑，对于有归属建筑的企业只需要传建筑一条数据即可
                    if (fiveChannelSize > 0) {
                        SyncTool.doSync(num, i -> {
                            int startIndex = (i - 1) * batchSize;
                            int endFiveIndex = Math.min(batchSize * i, fiveChannelSize);
                            if (endFiveIndex > 0 && endFiveIndex <= fiveChannelSize && num <= fiveSize) {
                                List<PoiChannelModel> poiChannelModels = poiFiveList.subList(startIndex, endFiveIndex);
                                List<String> result = iPoiScenarioChannelService.isBuildPoiId(poiChannelModels);
                                copyOnWriteArrayList.addAll(result);
                            }
                        });
                    }
                    if (copyOnWriteArrayList.size() > 0) {
                        throw new CommonException("下述poiId有归属建筑,只需传其归属建筑数据即可" + copyOnWriteArrayList);
                    }
                    //校验poi是否有归属的建筑，以及归属的建筑是否正确
                    if (fiveChannelSize > 0) {
                        SyncTool.doSync(num, i -> {
                            int startIndex = (i - 1) * batchSize;
                            int endFiveIndex = Math.min(batchSize * i, fiveChannelSize);
                            if (endFiveIndex > 0 && endFiveIndex <= fiveChannelSize && num <= fiveSize) {
                                List<PoiChannelModel> poiChannelModels = poiFiveList.subList(startIndex, endFiveIndex);
                                List<PoiChannelModel> result = iPoiScenarioChannelService.hasExistBuildPoiId(poiChannelModels);
                                copyOnWriteArrayList.addAll(result.stream().map(PoiChannelModel::getPoiId).collect(Collectors.toList()));
                            }
                        });
                    }
                    if (copyOnWriteArrayList.size() > 0) {
                        throw new CommonException("下述poiId所对应的归属建筑poiId不正确" + copyOnWriteArrayList);
                    }
                    //校验新增或更新的条数
                    SyncTool.doSync(num, i -> {
                        int startIndex = (i - 1) * batchSize;
                        int endStreetIndex = Math.min(batchSize * i, streetChannelSize);
                        if (endStreetIndex > 0 && endStreetIndex <= streetChannelSize && num <= streetSize) {
                            List<String> subList = poiStreetList.stream().map(PoiChannelModel::getPoiId).collect(Collectors.toList()).subList(startIndex, endStreetIndex);
                            int count = iPoiScenarioChannelService.selectCount(subList);
                            updateStreetCount.addAndGet(count);
                        }
                    });
                    //分别计算新增和更新的总个数
                    updateTotal[0] = updateStreetCount.get() + updateFiveCount.get();
                    insertTotal[0] = (streetChannelSize + fiveChannelSize) - updateTotal[0];
                }
            }).sheet().headRowNumber(2).doRead();
        } catch (IOException e) {
            log.error("异常：", e);
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    log.error("异常：", e);
                }
            }
        }
        PoiNumberCountResponse response = new PoiNumberCountResponse();
        response.setInsertCount(insertTotal[0]);
        response.setUpdateCount(updateTotal[0]);
        log.debug("人员导入确认返回值，{}", response);
        return Result.okData(response);
    }

    @Override
    public OpticalModem scanOpticalModem(String devType, String terminalNo) {
        log.debug("光猫扫描前端传入的参数，{}，{}", devType, terminalNo);
        if (opticalModemEnabled) {
            CloseableHttpClient httpClient = HttpClients.createDefault();
            try {
                HttpPost httpPost = new HttpPost(opticalModemUrl);
                //用json方式发送
                Map<String, String> map = new HashMap<>();
                map.put("devtype", devType);
                map.put("terminalno", terminalNo);
                String requestUrl = JSONUtil.toJsonStr(map);
                log.debug("调用光猫扫描接口json请求参数 {}", requestUrl);
                StringEntity jsonEntity = new StringEntity(requestUrl, StandardCharsets.UTF_8);
                jsonEntity.setContentType(ContentType.APPLICATION_JSON.getMimeType());
                httpPost.setEntity(jsonEntity);
                // 发送请求并获取响应
                HttpResponse response = httpClient.execute(httpPost);
                log.debug("光猫扫描接口返回的response值：{}", JSONUtil.toJsonStr(response));
                // 处理响应
                int statusCode = response.getStatusLine().getStatusCode();
                if (statusCode == 200) {
                    String responseBody = EntityUtils.toString(response.getEntity());
                    log.debug("光猫扫描接口responseBody转为string值：{}", responseBody);
                    OpticalModem opticalModem = JSONUtil.toBean(responseBody, OpticalModem.class);
                    if ("1".equals(opticalModem.getDealFlag())) {
                        throw new CommonException("该设备码没有在系统纳管");
                    }
                    log.debug("光猫扫描转为实体类的值，{}", opticalModem);
                    //如果返回为null给前端返回空字符串
                    if (StringUtils.isEmpty(opticalModem.getAccount()) || "NULL".equals(opticalModem.getAccount())) {
                        opticalModem.setAccount("");
                        return opticalModem;
                    }
                    return opticalModem;
                }
            } catch (Exception e) {
                log.debug("光猫扫描接口报错，{}", e.getMessage());
                e.printStackTrace();
                throw new CommonException(e);
            } finally {
                try {
                    httpClient.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        //本地和测试写死
        if (!opticalModemEnabled) {
            if (terminalNo.equals("123")) {
                throw new CommonException("光猫查询接口报错:未查询到设备信息！！！");
            }
            return OpticalModem.builder()
                    .dealFlag("0")
                    .model("中兴网关-ZXHN F6610M0")
                    .isyy("否")
                    .vendor("中兴")
                    .devname("devname")
                    .type("type")
                    .godownname("godownname")
                    .citycode("citycode")
                    .statustrip("statustrip")
                    .isxgpon("否")
                    .terminalno("ZTEGD3B53EB8")
                    .countycode("广饶")
                    .account("19862985526")
                    .dealDesc("查询成功")
                    .build();
        }
        return OpticalModem.builder().account("").build();
    }

    @Override
    public PoiCountResponse selectPoiCount(PoiCountRequest poiCountRequest) {
        log.debug("首页个数统计接口入参，{}", poiCountRequest);
        Integer level = uniAddrRegionService.selectLevel(poiCountRequest.getCodeStr());
        //统计宽带客户数
        Integer kdClientTotal = iPoiScenarioService.selectKdClientTotal(poiCountRequest, ComConstant.TABLES.get(0), level);
        //统计六大场景个数
        List<PoiSceneCount> list = iPoiScenarioService.selectSceneCountSub(poiCountRequest, ComConstant.TABLES.get(0), level);
        //计算我的摸排数量
        Integer kwPoiTotal = iPoiScenarioService.selectMyselfNumber(poiCountRequest, ComConstant.TABLES.get(0), level);
        PoiCountResponse poiCountResponse = new PoiCountResponse();
        int poiTotal = 0;
        int unKwPoiTotal = 0;
        log.debug("我的摸排个数，{}", kwPoiTotal);
        ArrayList<PoiCountResponse.SixSceneCount> sixSceneCounts = new ArrayList<>();
        //处理集合，计算六大场景个数
        for (PoiSceneCount entity : list) {
            Integer kwState = entity.getKwState();
            int poiCount = entity.getPoiCount();
            //计算总个数
            poiTotal += poiCount;
            //计算未摸排总个数
            if (kwState != null && kwState == 0) {
                unKwPoiTotal += poiCount;
            }
        }

        // 使用流操作和groupingBy进行按类型和是否勘误字段统计总个数
        Map<String, Map<Integer, Integer>> sceneTypeCounts = list.stream()
                .filter(poiSceneCount -> poiSceneCount.getType() != null)
                .collect(Collectors.groupingBy(
                        PoiSceneCount::getType,
                        Collectors.groupingBy(
                                PoiSceneCount::getKwState,
                                Collectors.summingInt(PoiSceneCount::getPoiCount)
                        )
                ));
        //将商业综合体结果合并到商务楼宇里面
        mergeTypes(sceneTypeCounts, ScenesStatus.BUSINESS.getDesc(), ScenesStatus.COMPLEX.getDesc());
        // 输出统计结果
        sceneTypeCounts.forEach((type, correctedMap) -> {
            PoiCountResponse.SixSceneCount sixSceneCount = new PoiCountResponse.SixSceneCount();
            correctedMap.forEach((isCorrected, count) -> {
                if (isCorrected == 1) {
                    sixSceneCount.setKwPoiTotal(count);
                } else {
                    sixSceneCount.setUnKwPoiTotal(count);
                }
                sixSceneCount.setType(type);
            });
            sixSceneCounts.add(sixSceneCount);
        });
        poiCountResponse.setPoiTotal(poiTotal);
        poiCountResponse.setKwPoiTotal(kwPoiTotal);
        poiCountResponse.setUnKwPoiTotal(unKwPoiTotal);
        poiCountResponse.setKdClientTotal(kdClientTotal);
        poiCountResponse.setSceneCounts(sixSceneCounts);
        log.debug("首页统计返回的结果，{}", poiCountResponse);
        return poiCountResponse;
    }

    @Override
    public PoiCountToWgtResponse selectPoiCountToWgt(PoiCountRequest poiCountRequest) {
        log.info("首页个数统计接口入参，{}", poiCountRequest);
        LambdaQueryWrapper<ExpressRegion> expressRegionWrapper = new LambdaQueryWrapper<>();
        expressRegionWrapper.select(ExpressRegion::getLevel).eq(ExpressRegion::getCode, poiCountRequest.getCodeStr());
        ExpressRegion expressRegion = iExpressRegionService.getOne(expressRegionWrapper);
        if (expressRegion == null) {
            log.info("传递的区域编码,{}不正确", poiCountRequest);
            throw new CommonException("传递的区域编码不正确！");
        }
        int level = Integer.parseInt(expressRegion.getLevel());
        //统计六大场景个数
        List<PoiSceneCount> list = iPoiScenarioService.selectSceneCountSub(poiCountRequest, ComConstant.TABLES.get(0), level);
        PoiCountToWgtResponse poiCountResponse = new PoiCountToWgtResponse();
        ArrayList<PoiCountToWgtResponse.SixSceneCount> sixSceneCounts = new ArrayList<>();
        // 使用流操作和groupingBy进行按类型和是否勘误字段统计总个数
        Map<String, Map<Integer, Integer>> sceneTypeCounts = list.stream()
                .filter(poiSceneCount -> poiSceneCount.getType() != null)
                .collect(Collectors.groupingBy(
                        PoiSceneCount::getType,
                        Collectors.groupingBy(
                                PoiSceneCount::getKwState,
                                Collectors.summingInt(PoiSceneCount::getPoiCount)
                        )
                ));
        //将商业综合体结果合并到商务楼宇里面
        mergeTypes(sceneTypeCounts, ScenesStatus.BUSINESS.getDesc(), ScenesStatus.COMPLEX.getDesc());
        // 输出统计结果
        sceneTypeCounts.forEach((type, correctedMap) -> {
            PoiCountToWgtResponse.SixSceneCount sixSceneCount = new PoiCountToWgtResponse.SixSceneCount();
            correctedMap.forEach((isCorrected, count) -> {
                if (isCorrected == 1) {
                    sixSceneCount.setKwPoiTotal(count);
                } else {
                    sixSceneCount.setUnKwPoiTotal(count);
                }
                sixSceneCount.setType(type);
            });
            sixSceneCounts.add(sixSceneCount);
        });
        poiCountResponse.setSceneCounts(sixSceneCounts);
        log.info("首页统计返回的结果，{}", poiCountResponse);
        return poiCountResponse;
    }

    @Override
    public PoiSpecificCountResponse selectSpecificPoiCount(PoiCountRequest poiCountRequest) {
        log.debug("具体类型头部信息入参，{}", poiCountRequest);
        Integer level = uniAddrRegionService.selectLevel(poiCountRequest.getCodeStr());
        PoiSpecificCountResponse response = new PoiSpecificCountResponse();
        //依次对应建筑和企业个数、随访、未随访个数、异网宽带数、我网宽带数、我网客户数、摸排手机号总数、摸排宽带总数
        int[] accumulators = new int[9];
        List<PoiSceneCount> list = iPoiScenarioService.selectSpecificSceneCount(poiCountRequest, ComConstant.TABLES.get(0), level);
        List<PoiSceneCount> poiSixCount = iPoiScenarioService.selectSpecificSceneKwPoiCount(poiCountRequest, ComConstant.TABLES.get(0), level);
        poiSixCount.forEach(entity -> {
            // 建筑和企业个数赋值
            if (entity.getIsBuild() != null && entity.getIsBuild() == 1) {
                accumulators[0] += entity.getPoiCount();
                accumulators[1] += entity.getPoiCount();
            } else if (entity.getIsBuild() != null && entity.getIsBuild() == 0) {
                accumulators[1] += entity.getPoiCount();
            }
            // 随访、未随访个数统计
            if (entity.getKwState() != null && entity.getKwState() == 1) {
                accumulators[2] += entity.getPoiCount();
            } else if (entity.getKwState() != null && entity.getKwState() == 0) {
                accumulators[3] += entity.getPoiCount();
            }
        });
        list.forEach(entity -> {
            if (entity.getBusinessState() == null || entity.getBusinessState() != 2) {
                // 异网宽带数、我网宽带数
                Integer belongOperator = entity.getBelongOperator();
                if (belongOperator != null && belongOperator == 0) {
                    accumulators[4] += entity.getPoiCount(); // 我网宽带数
                    accumulators[8] += entity.getPoiCount();
                } else if (belongOperator != null && (belongOperator == 1 || belongOperator == 2 || belongOperator == 3)) {
                    accumulators[5] += entity.getPoiCount(); // 异网宽带数
                    accumulators[8] += entity.getPoiCount();
                } else {
                    accumulators[8] += entity.getPoiCount();
                }
                // 我网客户数
                if (entity.getDzBelongOperator() != null && entity.getDzBelongOperator() == 0) {
                    accumulators[6] += entity.getPoiCount();
                    accumulators[7] += entity.getPoiCount();
                } else {
                    //摸排手机号总数
                    accumulators[7] += entity.getPoiCount();
                }
            }
        });
        // 将累加器中的值分别设置到 response 对象中
        response.setBuildTotal(accumulators[0]);
        response.setUnBuildTotal(accumulators[1]);
        response.setKwPoiTotal(accumulators[2]);
        response.setUnKwPoiTotal(accumulators[3]);
        response.setKdClientTotal(accumulators[4]);
        response.setKdOtherClientTotal(accumulators[5]);
        response.setDzBelongOperatorTotal(accumulators[6]);
        //客户渗透率
        if (accumulators[7] != 0) {
            double result = (double) accumulators[6] / accumulators[7];
            String formattedResult = String.format("%.2f", result);
            double finalResult = Double.parseDouble(formattedResult);
            response.setClientRate(finalResult);
        }
        //宽带渗透率
        if (accumulators[8] != 0) {
            double result = (double) accumulators[4] / accumulators[8];
            String formattedResult = String.format("%.2f", result);
            double finalResult = Double.parseDouble(formattedResult);
            response.setKdRate(finalResult);
        }
        log.debug("具体类型个数统计信息返回，{}", response);
        return response;
    }

    @Override
    public TaskDetailResponse selectBuildDetailInfo(PoiDetailRequest request) {
        log.debug("app查看详情接口入参{}", request);
        String type = request.getType();
        String id = request.getId();
        //先去草稿表里查之前是否摸排过
        String telNum = request.getTelNum();
        QueryWrapper<PoiScenarioProofreadDraft> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(PoiScenarioProofreadDraft::getPoiScenarioId,id).eq(PoiScenarioProofreadDraft::getKwPhone,telNum);
        PoiScenarioProofreadDraft poiScenarioProofreadDraft = draftService.getBaseMapper().selectOne(wrapper);
        if (poiScenarioProofreadDraft!=null){
            String result = poiScenarioProofreadDraft.getContent();
            if (StringUtils.isNotEmpty(result)){
                PoiDraftRequest content = JSONUtil.toBean(result, PoiDraftRequest.class);
                TaskDetailResponse response = new TaskDetailResponse();
                BeanUtils.copyProperties(content,response);
                //查一下该条数据的归属人，基础信息应该用归属人的，商机用当前摸排人摸排的数据
                BelongPeopleResponse belongPeopleResponse = iPoiScenarioProofreadService.selectBelongKwPhone(id, type);
                if (belongPeopleResponse!=null && !request.getTelNum().equals(belongPeopleResponse.getKwPhone())){
                    TaskDetailResponse taskDetailResponse = iPoiScenarioService.queryTaskDetailById(id);
                    BeanUtils.copyProperties(taskDetailResponse,response,"base64Infos");
                    response.setBusinessContentList(content.getBusinessContentList());
                    response.setBusinessContent(content.getBusinessContent());
                    response.setBelongKwPhone(belongPeopleResponse.getKwPhone());
                    if (content.getIntentionInfo()!=null){
                        response.setIntentionInfo(content.getIntentionInfo());
                    }
                }
                response.setChainId(poiScenarioProofreadDraft.getProofreadId());
                response.setDraftUpdateTime(poiScenarioProofreadDraft.getUpdateTime());
                log.debug("暂存接口值返回{}",response);
                return response;
            }
        }
        TaskDetailResponse taskDetailResponse = null;
        if (fromDescription(type).equals(ScenesStatus.STREET)) {
            taskDetailResponse = iPoiScenarioService.queryTaskDetailById(id);
            log.debug("沿街商铺详情信息第一步查询完毕！");
        } else {
            taskDetailResponse = iPoiScenarioService.queryTaskDetailById(id);
            //替换原数据的商业综合体--->商务楼宇
            if (taskDetailResponse != null && ScenesStatus.COMPLEX.getDesc().equals(taskDetailResponse.getType())) {
                taskDetailResponse.setType(ScenesStatus.BUSINESS.getDesc());
            }
            //判断该点是否是建筑，如果是建筑需要处理宽带渗透率、摸排情况
            if (taskDetailResponse != null && taskDetailResponse.getIsBuild() == 1) {
                List<PoiSceneCount> poiSceneCounts = iPoiScenarioService.selectBuildCount(Collections.singletonList(taskDetailResponse.getPoiId()));
                //已随访，未随访
                String poiId = taskDetailResponse.getPoiId();
                int belongOperatorZeroTotal = 0;
                int belongOperatorTotal = 0;
                for (PoiSceneCount poiSceneCount : poiSceneCounts) {
                    if (poiId.equals(poiSceneCount.getPoiId())) {
                        //随访个数补充
                        if (poiSceneCount.getKwState() == 1) {
                            taskDetailResponse.setKwPoiTotal(taskDetailResponse.getKwPoiTotal() + poiSceneCount.getPoiCount());
                        }
                        if (poiSceneCount.getKwState() == 0) {
                            taskDetailResponse.setUnKwPoiTotal(taskDetailResponse.getUnKwPoiTotal() + poiSceneCount.getPoiCount());
                        }
                        //我网宽带个数
                        if (poiSceneCount.getBelongOperator() != null && poiSceneCount.getBelongOperator().equals(0)) {
                            belongOperatorZeroTotal += poiSceneCount.getPoiCount();
                        }
                        belongOperatorTotal += poiSceneCount.getPoiCount();
                    }
                }
                if (belongOperatorTotal != 0) {
                    double result = (double) belongOperatorZeroTotal / belongOperatorTotal;
                    String formattedResult = String.format("%.2f", result);
                    double finalResult = Double.parseDouble(formattedResult);
                    taskDetailResponse.setKdRate(finalResult);
                }
            }
        }
        //未勘误--需要补充网络是否覆盖、路巷街、门牌号
        if (taskDetailResponse != null && taskDetailResponse.getKwState() != null && taskDetailResponse.getKwState() == 0) {
            Integer zoneCodeFlag = iPoiGovernmentService.selectZoneTypeByPoiId(taskDetailResponse.getPoiId());
            taskDetailResponse.setIsZoneCode(zoneCodeFlag);
            //处理路巷街、门牌号
            RoadInfoRequest roadInfoRequest = new RoadInfoRequest();
            BeanUtils.copyProperties(request,roadInfoRequest);
            roadInfoRequest.setPoiId(taskDetailResponse.getPoiId());
            RoadInfoResponse roadInfoResponse = iPoiGovernmentService.selectRoadInfo(roadInfoRequest);
            log.info("查询的路巷街门牌号{}",roadInfoResponse);
            BeanUtils.copyProperties(roadInfoResponse,taskDetailResponse);
        }
        //已随访 查询该随访poi归属人（首次随访）
        if (taskDetailResponse != null && taskDetailResponse.getKwState() != null && taskDetailResponse.getKwState() == 1) {
            BelongPeopleResponse response = iPoiScenarioProofreadService.selectBelongKwPhone(id, type);
            log.debug("详情接口获取到的归属人工号信息，{}", response);
            if (response != null && StringUtils.isNotEmpty(response.getKwPhone())) {
                taskDetailResponse.setBelongKwPhone(response.getKwPhone());
            }
        }
        String chainId = UUID.randomUUID().toString().replace("-", "");
        if (StringUtils.isEmpty(chainId)){
            throw new CommonException("生成序列号异常！");
        }
        if (taskDetailResponse != null) {
            taskDetailResponse.setChainId(chainId);
        }
        taskDetailResponse.setIntentionInfo(null);
        log.debug("建筑详情接口返回,{}", taskDetailResponse);
        return taskDetailResponse;
    }

    @Override
    public IPage<PoiListResponse> poiSettledList(PoiPageRequest request) {
        log.info("入住企业入参，{}", request);
        // 判断经纬度是否有效
        if (!isValid(String.format("POINT(%s %s)", request.getLon(), request.getLat()))) {
            log.error("当前传入经纬度无效");
            throw new CommonException("当前传入经纬度无效");
        }
        IPage<PoiScenario> poiScenarioIPage = new Page<>(request.getPageNum(), request.getPageSize());
        IPage<PoiListResponse> responseIPage = iPoiScenarioService.selectPoiSettledPage(poiScenarioIPage, request);

        List<PoiListResponse> records = responseIPage.getRecords();
        records.forEach(record -> {
            if (record.getKwState() != null && record.getKwState() == 0) {
                record.setKwTime(null);
            }
        });
        return responseIPage.setRecords(records);
    }

    @Override
    public List<BuildingDetailResponse> buildingDetailQuery(BuildDetailRequest request) {
        log.debug("楼宇明细查询入参，{}", request);
        List<BuildingDetailResponse> buildingDetailResponses = iPoiScenarioService.buildingDetailSelect(request);
        log.debug("楼宇明细查询返回结果，{}", buildingDetailResponses.size());
        return buildingDetailResponses;
    }

    @Override
    public LinkedHashMap<String, String> exportExcelHeader() {
        LinkedHashMap<String, String> map = new LinkedHashMap<>();
        Field[] fields = ScenesPageDto.class.getDeclaredFields();
        for (Field field : fields) {
            ExcelProperty annotation = field.getAnnotation(ExcelProperty.class);
            if (annotation != null) {
                String value = annotation.value()[0];
                String key = field.getName();
                //例如 poiName---点位名称(修改前)
                map.put(key, value);
            }
        }
        return map;
    }

    @Override
    public List<KwPeopleRecord> selectKwPeopleRecord(String id, String type) {
        log.debug("勘误记录查询入参，{}，{}", id, type);
        String table = ComConstant.TABLES.get(0);
        return iPoiScenarioService.kwPeopleRecordSelect(id, table, type);
    }

    @Override
    public List<TogetherResponse> selectIndexQueryTogetherData(IndexTogetherRequest request) {
        log.debug("app聚合入参，{}", request);
        BigDecimal rtLon = request.getRtLon();
        BigDecimal rtLat = request.getRtLat();
        BigDecimal lbLon = request.getLbLon();
        BigDecimal lbLat = request.getLbLat();
        if (Objects.isNull(rtLon) || Objects.isNull(rtLat) || Objects.isNull(lbLon) || Objects.isNull(lbLat)) {
            throw new CommonException("app聚合接口，可视区域坐标点有误！");
        }
        Integer level = uniAddrRegionService.selectLevel(request.getCodeStr());
        List<TogetherResponse> dataList = iPoiScenarioService.selectTogetherData(request, level);
        List<UniAddrRegion> regionList = getRegionListByCode(level, request.getFlag(), request.getCodeStr(), request.getRoleType());
        List<UniAddrRegion> collect = regionList.stream().filter(item -> !item.getName().contains("政企") && !item.getName().contains("校园") && !item.getName().contains("虚拟网格") && !item.getName().contains("商企网格")).collect(Collectors.toList());
        ArrayList<TogetherResponse> list = Lists.newArrayList();
        collect.forEach(regionAddr -> {
            TogetherResponse togetherResponse = new TogetherResponse();
            BeanUtils.copyProperties(regionAddr, togetherResponse);
            dataList.forEach(data -> {
                if (StringUtils.isNoneEmpty(data.getCode()) && data.getCode().equals(regionAddr.getCode())) {
                    togetherResponse.setTotal(data.getTotal());
                }
            });
            list.add(togetherResponse);
        });
        return list;
    }

    //根据权限返回能查询到的区县网格
    private List<UniAddrRegion> getRegionListByCode(Integer level, Integer flag, String codeStr, Integer roleType) {
        List<UniAddrRegion> list = Lists.newArrayList();
        if (level > 4) {
            throw new CommonException("传入的编码不对！");
        }
        //网格数据
        String gridCode = null;
        if (level == 4) {
            gridCode = codeStr;
            UniAddrRegion uniAddrRegion = uniAddrRegionService.selectRegionByCode(codeStr);
            codeStr = uniAddrRegion.getParentCode();
        }
        String[] parts = codeStr.split("\\.");
        if (flag > parts.length) {
            codeStr = String.join(".", parts);
        } else {
            codeStr = String.join(".", Arrays.copyOf(parts, flag));
        }
        if (flag == 1) { // 省级聚合
            list = uniAddrRegionService.selectRegionList(flag, codeStr);
        } else if (flag == 2) { // 市级聚合
            list = uniAddrRegionService.selectRegionList(flag, codeStr);
        } else if (flag == 3) { // 区级聚合
            list = uniAddrRegionService.selectRegionList(flag, codeStr);
        } else if (flag == 4) { // 网格级聚合
            list = uniAddrRegionService.selectRegionList(flag, codeStr);
            if (StringUtils.isNotEmpty(gridCode)) {
                String finalGridCode = gridCode;
                list = list.stream().filter(regionAddr -> regionAddr.getCode().equals(finalGridCode)).collect(Collectors.toList());
            }
        }
        return list;
    }
}
